Commit d403329c1714b870386a57485d49fdd65e49db4b

Authored by Evandro Junior
1 parent afa755fb

Library that works with proxy

Showing 31 changed files with 2034 additions and 0 deletions   Show diff stats
plugins/community_hub/tweeter_stream/.gemtest 0 → 100755
plugins/community_hub/tweeter_stream/.gitignore 0 → 100755
... ... @@ -0,0 +1,39 @@
  1 +*.gem
  2 +*.rbc
  3 +*.sw[a-p]
  4 +*.tmproj
  5 +*.tmproject
  6 +*.un~
  7 +*~
  8 +.Spotlight-V100
  9 +.Trashes
  10 +._*
  11 +.bundle
  12 +.config
  13 +.directory
  14 +.elc
  15 +.emacs.desktop
  16 +.emacs.desktop.lock
  17 +.redcar
  18 +.yardoc
  19 +Desktop.ini
  20 +Gemfile.lock
  21 +Icon?
  22 +InstalledFiles
  23 +Session.vim
  24 +\#*\#
  25 +_yardoc
  26 +auto-save-list
  27 +coverage
  28 +doc
  29 +lib/bundler/man
  30 +pkg
  31 +pkg/*
  32 +rdoc
  33 +spec/reports
  34 +test/tmp
  35 +test/version_tmp
  36 +tmp
  37 +tmtags
  38 +tramp
  39 +/nbproject/private/
0 40 \ No newline at end of file
... ...
plugins/community_hub/tweeter_stream/.travis.yml 0 → 100755
... ... @@ -0,0 +1,15 @@
  1 +bundler_args: --without development
  2 +language: ruby
  3 +rvm:
  4 + - 1.8.7
  5 + - 1.9.2
  6 + - 1.9.3
  7 + - 2.0.0
  8 + - jruby-head
  9 + - rbx-2
  10 + - ruby-head
  11 +matrix:
  12 + allow_failures:
  13 + - rvm: jruby-head
  14 + - rvm: ruby-head
  15 + fast_finish: true
... ...
plugins/community_hub/tweeter_stream/.twurlrc 0 → 100755
... ... @@ -0,0 +1,13 @@
  1 +---
  2 +profiles:
  3 + evandro:
  4 + QkiWnQvutoV63ty0Afg:
  5 + token: 8601482-U3qvrGvZmKgm5HnTCskdYU2bAoMPzNpXcLtdVzhKQx
  6 + consumer_key: QkiWnQvutoV63ty0Afg
  7 + username: evandro
  8 + consumer_secret: kCLHpOG2p3073mYsxrTYyvwkOulYbtIcxpQkthJU
  9 + secret: eCzPWQOcUdcADRmFjqQTIXPbmieOxMpXDj7RUS6mVrPru
  10 +configuration:
  11 + default_profile:
  12 + - evandro
  13 + - QkiWnQvutoV63ty0Afg
... ...
plugins/community_hub/tweeter_stream/COPYING 0 → 100755
... ... @@ -0,0 +1,18 @@
  1 +# Copyright (c) 2009 Marcel Molina <marcel@twitter.com>, Twitter, Inc.
  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 the
  5 +# Software without restriction, including without limitation the rights to use,
  6 +# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
  7 +# 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 IN
  17 +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18 +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
... ...
plugins/community_hub/tweeter_stream/Gemfile 0 → 100755
... ... @@ -0,0 +1,14 @@
  1 +source 'https://rubygems.org'
  2 +
  3 +gem 'jruby-openssl', :platforms => :jruby
  4 +gem 'rake'
  5 +
  6 +group :test do
  7 + gem 'coveralls', :require => false
  8 + gem 'mime-types', '~> 1.25', :platforms => :ruby_18
  9 + gem 'minitest', '>= 5'
  10 + gem 'rr', '>= 1.1'
  11 + gem 'simplecov', :require => false
  12 +end
  13 +
  14 +gemspec
... ...
plugins/community_hub/tweeter_stream/INSTALL 0 → 100755
... ... @@ -0,0 +1,18 @@
  1 ++-----------------------+
  2 +| Install with RubyGems |
  3 ++-----------------------+
  4 +
  5 + sudo gem i twurl --source http://rubygems.org
  6 +
  7 ++---------------------+
  8 +| Install from source |
  9 ++---------------------+
  10 +
  11 + rake dist:gem
  12 + sudo gem i pkg/twurl*gem
  13 +
  14 ++--------------+
  15 +| Dependencies |
  16 ++--------------+
  17 +
  18 + sudo gem i oauth
... ...
plugins/community_hub/tweeter_stream/README 0 → 100755
... ... @@ -0,0 +1,119 @@
  1 ++-------+
  2 +| Twurl |
  3 ++-------+
  4 +
  5 +Twurl is like curl, but tailored specifically for the Twitter API.
  6 +It knows how to grant an access token to a client application for
  7 +a specified user and then sign all requests with that access token.
  8 +
  9 +It also provides other development and debugging conveniences such
  10 +as defining aliases for common requests, as well as support for
  11 +multiple access tokens to easily switch between different client
  12 +applications and Twitter accounts.
  13 +
  14 ++-----------------+
  15 +| Getting Started |
  16 ++-----------------+
  17 +
  18 +The first thing you have to do is register an OAuth application
  19 +to get a consumer key and secret.
  20 +
  21 + http://dev.twitter.com/apps/new
  22 +
  23 +When you have your consumer key and its secret you authorize
  24 +your Twitter account to make API requests with your consumer key
  25 +and secret.
  26 +
  27 + % twurl authorize --consumer-key key \
  28 + --consumer-secret secret
  29 +
  30 +This will return an URL that you should open up in your browser.
  31 +Authenticate to Twitter, and then enter the returned PIN back into
  32 +the terminal. Assuming all that works well, you will beauthorized
  33 +to make requests with the API. Twurl will tell you as much.
  34 +
  35 +If your consumer application has xAuth enabled, then you can use
  36 +a variant of the above
  37 +
  38 + % twurl authorize -u username -p password \
  39 + --consumer-key key \
  40 + --consumer-secret secret
  41 +
  42 +And, again assuming your username, password, key and secret is
  43 +correct, will authorize you in one step.
  44 +
  45 ++-----------------+
  46 +| Making Requests |
  47 ++-----------------+
  48 +
  49 +The simplest request just requires that you specify the path you
  50 +want to request.
  51 +
  52 + % twurl /1.1/statuses/home_timeline.json
  53 +
  54 +Similar to curl, a GET request is performed by default.
  55 +
  56 +You can implicitly perform a POST request by passing the -d option,
  57 +which specifies POST parameters.
  58 +
  59 + % twurl -d 'status=Testing twurl' /1.1/statuses/update.json
  60 +
  61 +You can explicitly specify what request method to perform with
  62 +the -X (or --request-method) option.
  63 +
  64 + % twurl -X POST /1.1/statuses/destroy/1234567890.json
  65 +
  66 ++------------------+
  67 +| Creating aliases |
  68 ++------------------+
  69 +
  70 + % twurl alias h /1.1/statuses/home_timeline.json
  71 +
  72 +You can then use "h" in place of the full path.
  73 +
  74 + % twurl h
  75 +
  76 +Paths that require additional options such as request parameters for example can
  77 +be used with aliases the same as with full explicit paths, just as you might
  78 +expect.
  79 +
  80 + % twurl alias tweet /1.1/statuses/update.json
  81 + % twurl tweet -d "status=Aliases in twurl are convenient"
  82 +
  83 ++-------------------------------+
  84 +| Changing your default profile |
  85 ++-------------------------------+
  86 +
  87 +The first time you authorize a client application to make requests on behalf of your account, twurl stores your access token information in its .twurlrc file. Subsequent requests will use this profile as the default profile. You can use the 'accounts' subcommand to see what client applications have been authorized for what user names:
  88 +
  89 + % twurl accounts
  90 + noradio
  91 + HQsAGcBm5MQT4n6j7qVJw
  92 + hhC7Koy2zRsTZvQh1hVlSA (default)
  93 + testiverse
  94 + guT9RsJbNQgVe6AwoY9BA
  95 +
  96 +Notice that one of those consumer keys is marked as the default. To change the default use the 'set' subcommand, passing then either just the username, if it's unambiguous, or the username and consumer key pair if it isn't unambiguous:
  97 +
  98 + % twurl set default testiverse
  99 + % twurl accounts
  100 + noradio
  101 + HQsAGcBm5MQT4n6j7qVJw
  102 + hhC7Koy2zRsTZvQh1hVlSA
  103 + testiverse
  104 + guT9RsJbNQgVe6AwoY9BA (default)
  105 +
  106 + % twurl set default noradio HQsAGcBm5MQT4n6j7qVJw
  107 + % twurl accounts
  108 + noradio
  109 + HQsAGcBm5MQT4n6j7qVJw (default)
  110 + hhC7Koy2zRsTZvQh1hVlSA
  111 + testiverse
  112 + guT9RsJbNQgVe6AwoY9BA
  113 +
  114 ++--------------+
  115 +| Contributors |
  116 ++--------------+
  117 +
  118 +Marcel Molina <marcel@twitter.com> / @noradio
  119 +Erik Michaels-Ober / @sferik
... ...
plugins/community_hub/tweeter_stream/Rakefile 0 → 100755
... ... @@ -0,0 +1,12 @@
  1 +require 'rake/testtask'
  2 +require 'rubygems/package_task'
  3 +require 'bundler'
  4 +
  5 +task :default => :test
  6 +
  7 +Rake::TestTask.new do |test|
  8 + test.pattern = 'test/*_test.rb'
  9 + test.verbose = true
  10 +end
  11 +
  12 +Bundler::GemHelper.install_tasks
... ...
plugins/community_hub/tweeter_stream/lib/cli.rb 0 → 100755
... ... @@ -0,0 +1,368 @@
  1 +module Twurl
  2 + class CLI
  3 + SUPPORTED_COMMANDS = %w(authorize accounts alias set)
  4 + DEFAULT_COMMAND = 'request'
  5 + PATH_PATTERN = /^\/\w+/
  6 + PROTOCOL_PATTERN = /^\w+:\/\//
  7 + README = File.dirname(__FILE__) + '/../../README'
  8 + @output ||= STDOUT
  9 + class NoPathFound < Exception
  10 + end
  11 +
  12 + class << self
  13 + attr_accessor :output
  14 +
  15 + def run(args)
  16 + begin
  17 + options = parse_options(args)
  18 + rescue NoPathFound => e
  19 + exit
  20 + end
  21 + dispatch(options)
  22 + end
  23 +
  24 + def dispatch(options)
  25 + client = OAuthClient.load_from_options(options)
  26 + controller = case options.command
  27 + when 'authorize'
  28 + AuthorizationController
  29 + when 'accounts'
  30 + AccountInformationController
  31 + when 'alias'
  32 + AliasesController
  33 + when 'set'
  34 + ConfigurationController
  35 + when 'request'
  36 + RequestController
  37 + end
  38 + controller.dispatch(client, options)
  39 + rescue Twurl::Exception => exception
  40 + abort(exception.message)
  41 + end
  42 +
  43 + def parse_options(args)
  44 + arguments = args.dup
  45 +
  46 + Twurl.options = Options.new
  47 + Twurl.options.trace = false
  48 + Twurl.options.data = {}
  49 + Twurl.options.headers = {}
  50 + Twurl.options.upload = {}
  51 + Twurl.options.upload['file'] = []
  52 +
  53 + option_parser = OptionParser.new do |o|
  54 + o.extend AvailableOptions
  55 +
  56 + o.banner = <<-BANNER
  57 +Usage: twurl authorize --consumer-key key --consumer-secret secret
  58 + twurl [options] /1.1/statuses/home_timeline.json
  59 +
  60 +Supported Commands: #{SUPPORTED_COMMANDS.sort.join(', ')}
  61 + BANNER
  62 +
  63 + o.section "Getting started:" do
  64 + tutorial
  65 + end
  66 +
  67 + o.section "Authorization options:" do
  68 + username
  69 + password
  70 + consumer_key
  71 + consumer_secret
  72 + access_token
  73 + token_secret
  74 + end
  75 +
  76 + o.section "Common options:" do
  77 + trace
  78 + data
  79 + headers
  80 + host
  81 + quiet
  82 + disable_ssl
  83 + request_method
  84 + help
  85 + version
  86 + proxy
  87 + file
  88 + filefield
  89 + base64
  90 + read_timeout
  91 + end
  92 + end
  93 +
  94 + arguments = option_parser.parse!(args)
  95 + Twurl.options.command = extract_command!(arguments)
  96 + Twurl.options.path = extract_path!(arguments)
  97 +
  98 + if Twurl.options.command == DEFAULT_COMMAND and Twurl.options.path.nil?
  99 + CLI.puts option_parser
  100 + raise NoPathFound, "No path found"
  101 + end
  102 +
  103 + Twurl.options.subcommands = arguments
  104 + Twurl.options
  105 + end
  106 +
  107 + def output
  108 + if Twurl.options && Twurl.options.output
  109 + Twurl.options.output
  110 + else
  111 + @output
  112 + end
  113 + end
  114 +
  115 + def print(*args, &block)
  116 + output.print(*args, &block)
  117 + output.flush if output.respond_to?(:flush)
  118 + end
  119 +
  120 + def puts(*args, &block)
  121 + output.puts(*args, &block)
  122 + output.flush if output.respond_to?(:flush)
  123 + end
  124 +
  125 + def prompt_for(label)
  126 + system "stty -echo"
  127 + CLI.print "#{label}: "
  128 + result = STDIN.gets.chomp
  129 + CLI.puts
  130 + result
  131 + rescue Interrupt
  132 + exit
  133 + ensure
  134 + system "stty echo"
  135 + end
  136 +
  137 + private
  138 + def extract_command!(arguments)
  139 + if SUPPORTED_COMMANDS.include?(arguments.first)
  140 + arguments.shift
  141 + else
  142 + DEFAULT_COMMAND
  143 + end
  144 + end
  145 +
  146 + def extract_path!(arguments)
  147 + path = nil
  148 + arguments.each_with_index do |argument, index|
  149 + if argument[PATH_PATTERN]
  150 + path_with_params = arguments.slice!(index)
  151 + path, params = path_with_params.split("?", 2)
  152 + if params
  153 + path += "?" + escape_params(params)
  154 + end
  155 + break
  156 + end
  157 + end
  158 + path
  159 + end
  160 +
  161 + def escape_params(params)
  162 + split_params = params.split("&").map do |param|
  163 + key, value = param.split('=', 2)
  164 + CGI::escape(key) + '=' + CGI::escape(value)
  165 + end
  166 + split_params.join("&")
  167 + end
  168 + end
  169 +
  170 + module AvailableOptions
  171 + def options
  172 + Twurl.options
  173 + end
  174 +
  175 + def section(heading, &block)
  176 + separator ""
  177 + separator heading
  178 +
  179 + instance_eval(&block)
  180 + end
  181 +
  182 + def tutorial
  183 + on('-T', '--tutorial', "Narrative overview of how to get started using Twurl") do
  184 + CLI.puts IO.read(README)
  185 + exit
  186 + end
  187 + end
  188 +
  189 + def consumer_key
  190 + on('-c', '--consumer-key [key]', "Your consumer key (required)") do |key|
  191 + options.consumer_key = key ? key : CLI.prompt_for('Consumer key')
  192 + end
  193 + end
  194 +
  195 + def consumer_secret
  196 + on('-s', '--consumer-secret [secret]', "Your consumer secret (required)") do |secret|
  197 + options.consumer_secret = secret ? secret : CLI.prompt_for('Consumer secret')
  198 + end
  199 + end
  200 +
  201 + def access_token
  202 + on('-a', '--access-token [token]', 'Your access token') do |token|
  203 + options.access_token = token
  204 + end
  205 + end
  206 +
  207 + def token_secret
  208 + on('-S', '--token-secret [secret]', "Your token secret") do |secret|
  209 + options.token_secret = secret
  210 + end
  211 + end
  212 +
  213 + def username
  214 + on('-u', '--username [username]', 'Username of account to authorize (required)') do |username|
  215 + options.username = username
  216 + end
  217 + end
  218 +
  219 + def password
  220 + on('-p', '--password [password]', 'Password of account to authorize (required)') do |password|
  221 + options.password = password ? password : CLI.prompt_for('Password')
  222 + end
  223 + end
  224 +
  225 + def trace
  226 + on('-t', '--[no-]trace', 'Trace request/response traffic (default: --no-trace)') do |trace|
  227 + options.trace = trace
  228 + end
  229 + end
  230 +
  231 + def data
  232 + on('-d', '--data [data]', 'Sends the specified data in a POST request to the HTTP server.') do |data|
  233 + data.split('&').each do |pair|
  234 + key, value = pair.split('=', 2)
  235 + options.data[key] = value
  236 + end
  237 + end
  238 + end
  239 +
  240 + def headers
  241 + on('-A', '--header [header]', 'Adds the specified header to the request to the HTTP server.') do |header|
  242 + key, value = header.split(': ')
  243 + options.headers[key] = value
  244 + end
  245 + end
  246 +
  247 + def host
  248 + on('-H', '--host [host]', 'Specify host to make requests to (default: api.twitter.com)') do |host|
  249 + if host[PROTOCOL_PATTERN]
  250 + protocol, protocolless_host = host.split(PROTOCOL_PATTERN, 2)
  251 + options.host = protocolless_host
  252 + else
  253 + options.host = host
  254 + end
  255 + end
  256 + end
  257 +
  258 + def quiet
  259 + on('-q', '--quiet', 'Suppress all output (default: output is printed to STDOUT)') do |quiet|
  260 + options.output = StringIO.new
  261 + end
  262 + end
  263 +
  264 + def disable_ssl
  265 + on('-U', '--no-ssl', 'Disable SSL (default: SSL is enabled)') do |use_ssl|
  266 + options.protocol = 'http'
  267 + end
  268 + end
  269 +
  270 + def request_method
  271 + on('-X', '--request-method [method]', 'Request method (default: GET)') do |request_method|
  272 + options.request_method = request_method.downcase
  273 + end
  274 + end
  275 +
  276 + def help
  277 + on_tail("-h", "--help", "Show this message") do
  278 + CLI.puts self
  279 + exit
  280 + end
  281 + end
  282 +
  283 + def version
  284 + on_tail("-v", "--version", "Show version") do
  285 + CLI.puts Version
  286 + exit
  287 + end
  288 + end
  289 +
  290 + def proxy
  291 + on('-P', '--proxy [proxy]', 'Specify HTTP proxy to forward requests to (default: No proxy)') do |proxy|
  292 + options.proxy = proxy
  293 + end
  294 + end
  295 +
  296 + def file
  297 + on('-f', '--file [path_to_file]', 'Specify the path to the file to upload') do |file|
  298 + if File.file?(file)
  299 + options.upload['file'] << file
  300 + else
  301 + CLI.puts "ERROR: File not found"
  302 + exit
  303 + end
  304 + end
  305 + end
  306 +
  307 + def filefield
  308 + on('-F', '--file-field [field_name]', 'Specify the POST parameter name for the file upload data (default: media)') do |filefield|
  309 + options.upload['filefield'] = filefield
  310 + end
  311 + end
  312 +
  313 + def base64
  314 + on('-b', '--base64', 'Encode the uploaded file as base64 (default: false)') do |base64|
  315 + options.upload['base64'] = base64
  316 + end
  317 + end
  318 +
  319 + def read_timeout
  320 + on('-y', '--read-timeout [read_timeout]', 'Http Read Timeout (default: Net::HTTP read_timeout)') do |read_timeout|
  321 + options.read_timeout = read_timeout.to_i
  322 + end
  323 + end
  324 + end
  325 + end
  326 +
  327 +
  328 + class Options < OpenStruct
  329 + DEFAULT_REQUEST_METHOD = 'get'
  330 + DEFAULT_HOST = 'api.twitter.com'
  331 + DEFAULT_PROTOCOL = 'https'
  332 +
  333 + def oauth_client_options
  334 + OAuthClient::OAUTH_CLIENT_OPTIONS.inject({}) do |options, option|
  335 + options[option] = send(option)
  336 + options
  337 + end
  338 + end
  339 +
  340 + def base_url
  341 + "#{protocol}://#{host}"
  342 + end
  343 +
  344 + def ssl?
  345 + protocol == 'https'
  346 + end
  347 +
  348 + def debug_output_io
  349 + super || STDERR
  350 + end
  351 +
  352 + def request_method
  353 + super || (data.empty? ? DEFAULT_REQUEST_METHOD : 'post')
  354 + end
  355 +
  356 + def protocol
  357 + super || DEFAULT_PROTOCOL
  358 + end
  359 +
  360 + def host
  361 + super || DEFAULT_HOST
  362 + end
  363 +
  364 + def proxy
  365 + super || nil
  366 + end
  367 + end
  368 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl.rb 0 → 100755
... ... @@ -0,0 +1,21 @@
  1 +require 'rubygems'
  2 +require 'oauth'
  3 +require 'optparse'
  4 +require 'ostruct'
  5 +require 'stringio'
  6 +require 'yaml'
  7 +
  8 +library_files = Dir[File.join(File.dirname(__FILE__), "/twurl/**/*.rb")].sort
  9 +library_files.each do |file|
  10 + require file
  11 +end
  12 +
  13 +module Twurl
  14 + @options ||= Options.new
  15 + class << self
  16 + attr_accessor :options
  17 + end
  18 +
  19 + class Exception < ::Exception
  20 + end
  21 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl/abstract_command_controller.rb 0 → 100755
... ... @@ -0,0 +1,16 @@
  1 +module Twurl
  2 + # Subclasses need to implement a `dispatch' instance method.
  3 + class AbstractCommandController
  4 + attr_reader :client, :options
  5 + class << self
  6 + def dispatch(*args, &block)
  7 + new(*args, &block).dispatch
  8 + end
  9 + end
  10 +
  11 + def initialize(client, options)
  12 + @client = client
  13 + @options = options
  14 + end
  15 + end
  16 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl/oauth_client.rb 0 → 100755
... ... @@ -0,0 +1,213 @@
  1 +module Twurl
  2 + class OAuthClient
  3 + class << self
  4 + def rcfile(reload = false)
  5 + if reload || @rcfile.nil?
  6 + @rcfile = RCFile.new
  7 + end
  8 + @rcfile
  9 + end
  10 +
  11 + def load_from_options(options)
  12 + if rcfile.has_oauth_profile_for_username_with_consumer_key?(options.username, options.consumer_key)
  13 + load_client_for_username_and_consumer_key(options.username, options.consumer_key)
  14 + elsif options.username || (options.command == 'authorize')
  15 + load_new_client_from_options(options)
  16 + else
  17 + load_default_client
  18 + end
  19 + end
  20 +
  21 + def load_client_for_username_and_consumer_key(username, consumer_key)
  22 + user_profiles = rcfile[username]
  23 + if user_profiles && attributes = user_profiles[consumer_key]
  24 + new(attributes)
  25 + else
  26 + raise Exception, "No profile for #{username}"
  27 + end
  28 + end
  29 +
  30 + def load_client_for_username(username)
  31 + if user_profiles = rcfile[username]
  32 + if user_profiles.values.size == 1
  33 + new(user_profiles.values.first)
  34 + else
  35 + raise Exception, "There is more than one consumer key associated with #{username}. Please specify which consumer key you want as well."
  36 + end
  37 + else
  38 + raise Exception, "No profile for #{username}"
  39 + end
  40 + end
  41 +
  42 + def load_new_client_from_options(options)
  43 + new(options.oauth_client_options.merge('password' => options.password, 'token' => options.access_token, 'secret' => options.token_secret))
  44 + end
  45 +
  46 + def load_default_client
  47 + raise Exception, "You must authorize first" unless rcfile.default_profile
  48 + load_client_for_username_and_consumer_key(*rcfile.default_profile)
  49 + end
  50 + end
  51 +
  52 + OAUTH_CLIENT_OPTIONS = %w[username consumer_key consumer_secret token secret]
  53 + attr_reader *OAUTH_CLIENT_OPTIONS
  54 + attr_reader :username, :password
  55 + def initialize(options = {})
  56 + @username = options['username']
  57 + @password = options['password']
  58 + @consumer_key = options['consumer_key']
  59 + @consumer_secret = options['consumer_secret']
  60 + @token = options['token']
  61 + @secret = options['secret']
  62 + configure_http!
  63 + end
  64 +
  65 + METHODS = {
  66 + :post => Net::HTTP::Post,
  67 + :get => Net::HTTP::Get,
  68 + :put => Net::HTTP::Put,
  69 + :delete => Net::HTTP::Delete,
  70 + :options => Net::HTTP::Options,
  71 + :head => Net::HTTP::Head,
  72 + :copy => Net::HTTP::Copy
  73 + }
  74 +
  75 + def perform_request_from_options(options, &block)
  76 + request_class = METHODS.fetch(options.request_method.to_sym)
  77 + request = request_class.new(options.path, options.headers)
  78 +
  79 + if options.upload && options.upload['file'].count > 0
  80 + boundary = "00Twurl" + rand(1000000000000000000).to_s + "lruwT99"
  81 + multipart_body = []
  82 + file_field = options.upload['filefield'] ? options.upload['filefield'] : 'media[]'
  83 +
  84 + options.data.each {|key, value|
  85 + multipart_body << "--#{boundary}\r\n"
  86 + multipart_body << "Content-Disposition: form-data; name=\"#{key}\"\r\n"
  87 + multipart_body << "\r\n"
  88 + multipart_body << value
  89 + multipart_body << "\r\n"
  90 + }
  91 +
  92 + options.upload['file'].each {|filename|
  93 + multipart_body << "--#{boundary}\r\n"
  94 + multipart_body << "Content-Disposition: form-data; name=\"#{file_field}\"; filename=\"#{File.basename(filename)}\"\r\n"
  95 + multipart_body << "Content-Type: application/octet-stream\r\n"
  96 + multipart_body << "Content-Transfer-Encoding: base64\r\n" if options.upload['base64']
  97 + multipart_body << "\r\n"
  98 +
  99 + if options.upload['base64']
  100 + enc = Base64.encode64(File.read(filename))
  101 + multipart_body << enc
  102 + else
  103 + multipart_body << File.read(filename)
  104 + end
  105 + }
  106 +
  107 + multipart_body << "\r\n--#{boundary}--\r\n"
  108 +
  109 + request.body = multipart_body.join
  110 + request['Content-Type'] = "multipart/form-data, boundary=\"#{boundary}\""
  111 + elsif options.data
  112 + request.set_form_data(options.data)
  113 + end
  114 +
  115 + request.oauth!(consumer.http, consumer, access_token)
  116 + consumer.http.read_timeout = options.read_timeout if options.read_timeout
  117 + consumer.http.request(request, &block)
  118 + end
  119 +
  120 + def exchange_credentials_for_access_token
  121 + response = begin
  122 + consumer.token_request(:post, consumer.access_token_path, nil, {}, client_auth_parameters)
  123 + rescue OAuth::Unauthorized
  124 + perform_pin_authorize_workflow
  125 + end
  126 + @token = response[:oauth_token]
  127 + @secret = response[:oauth_token_secret]
  128 + end
  129 +
  130 + def client_auth_parameters
  131 + {'x_auth_username' => username, 'x_auth_password' => password, 'x_auth_mode' => 'client_auth'}
  132 + end
  133 +
  134 + def perform_pin_authorize_workflow
  135 + @request_token = consumer.get_request_token
  136 + CLI.puts("Go to #{generate_authorize_url} and paste in the supplied PIN")
  137 + pin = gets
  138 + access_token = @request_token.get_access_token(:oauth_verifier => pin.chomp)
  139 + {:oauth_token => access_token.token, :oauth_token_secret => access_token.secret}
  140 + end
  141 +
  142 + def generate_authorize_url
  143 + request = consumer.create_signed_request(:get, consumer.authorize_path, @request_token, pin_auth_parameters)
  144 + params = request['Authorization'].sub(/^OAuth\s+/, '').split(/,\s+/).map { |p|
  145 + k, v = p.split('=')
  146 + v =~ /"(.*?)"/
  147 + "#{k}=#{CGI::escape($1)}"
  148 + }.join('&')
  149 + "#{Twurl.options.base_url}#{request.path}?#{params}"
  150 + end
  151 +
  152 + def pin_auth_parameters
  153 + {'oauth_callback' => 'oob'}
  154 + end
  155 +
  156 + def fetch_verify_credentials
  157 + access_token.get('/1.1/account/verify_credentials.json?include_entities=false&skip_status=true')
  158 + end
  159 +
  160 + def authorized?
  161 + oauth_response = fetch_verify_credentials
  162 + oauth_response.class == Net::HTTPOK
  163 + end
  164 +
  165 + def needs_to_authorize?
  166 + token.nil? || secret.nil?
  167 + end
  168 +
  169 + def save
  170 + verify_has_username
  171 + self.class.rcfile << self
  172 + end
  173 +
  174 + def verify_has_username
  175 + if username.nil? || username == ''
  176 + oauth_response = fetch_verify_credentials
  177 + oauth_response.body =~ /"screen_name"\s*:\s*"(.*?)"/
  178 + @username = $1
  179 + end
  180 + end
  181 +
  182 + def to_hash
  183 + OAUTH_CLIENT_OPTIONS.inject({}) do |hash, attribute|
  184 + if value = send(attribute)
  185 + hash[attribute] = value
  186 + end
  187 + hash
  188 + end
  189 + end
  190 +
  191 + def configure_http!
  192 + consumer.http.set_debug_output(Twurl.options.debug_output_io) if Twurl.options.trace
  193 + if Twurl.options.ssl?
  194 + consumer.http.use_ssl = true
  195 + consumer.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  196 + end
  197 + end
  198 +
  199 + def consumer
  200 + @consumer ||=
  201 + OAuth::Consumer.new(
  202 + consumer_key,
  203 + consumer_secret,
  204 + :site => Twurl.options.base_url,
  205 + :proxy => Twurl.options.proxy
  206 + )
  207 + end
  208 +
  209 + def access_token
  210 + @access_token ||= OAuth::AccessToken.new(consumer, token, secret)
  211 + end
  212 + end
  213 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl/rcfile.rb 0 → 100755
... ... @@ -0,0 +1,103 @@
  1 +module Twurl
  2 + class RCFile
  3 +
  4 + class << self
  5 + def directory
  6 + @@directory ||= File.expand_path('~')
  7 + end
  8 +
  9 + def directory=(dir)
  10 + @@directory = dir
  11 + end
  12 +
  13 + def file_path
  14 + Stream.file_path
  15 + end
  16 +
  17 + def load
  18 + YAML.load_file(file_path)
  19 + rescue Errno::ENOENT
  20 + default_rcfile_structure
  21 + end
  22 +
  23 + def default_rcfile_structure
  24 + {'profiles' => {}, 'configuration' => {}}
  25 + end
  26 + end
  27 +
  28 + attr_reader :data
  29 + def initialize
  30 + @data = self.class.load
  31 + end
  32 +
  33 + def set_path(p)
  34 + puts "entro set path #{p}"
  35 + @@file_path = p
  36 + end
  37 +
  38 + def empty?
  39 + data == self.class.default_rcfile_structure
  40 + end
  41 +
  42 + def save
  43 + File.open(self.class.file_path, File::RDWR|File::CREAT|File::TRUNC, 0600) do |rcfile|
  44 + rcfile.write data.to_yaml
  45 + end
  46 + end
  47 +
  48 + def [](username)
  49 + profiles[username]
  50 + end
  51 +
  52 + def profiles
  53 + data['profiles']
  54 + end
  55 +
  56 + def default_profile
  57 + configuration['default_profile']
  58 + end
  59 +
  60 + def default_profile=(profile)
  61 + configuration['default_profile'] = [profile.username, profile.consumer_key]
  62 + end
  63 +
  64 + def configuration
  65 + data['configuration']
  66 + end
  67 +
  68 + def alias(name, path)
  69 + data['aliases'] ||= {}
  70 + data['aliases'][name] = path
  71 + save
  72 + end
  73 +
  74 + def aliases
  75 + data['aliases']
  76 + end
  77 +
  78 + def alias_from_options(options)
  79 + options.subcommands.each do |potential_alias|
  80 + if path = alias_from_name(potential_alias)
  81 + break path
  82 + end
  83 + end
  84 + end
  85 +
  86 + def alias_from_name(name)
  87 + aliases[name]
  88 + end
  89 +
  90 + def has_oauth_profile_for_username_with_consumer_key?(username, consumer_key)
  91 + user_profiles = self[username]
  92 + !user_profiles.nil? && !user_profiles[consumer_key].nil?
  93 + end
  94 +
  95 + def <<(oauth_client)
  96 + client_from_file = self[oauth_client.username] || {}
  97 + client_from_file[oauth_client.consumer_key] = oauth_client.to_hash
  98 + (profiles[oauth_client.username] ||= {}).update(client_from_file)
  99 + self.default_profile = oauth_client unless default_profile
  100 + save
  101 + end
  102 + end
  103 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl/request_controller.rb 0 → 100755
... ... @@ -0,0 +1,20 @@
  1 +module Twurl
  2 + class RequestController < AbstractCommandController
  3 + NO_URI_MESSAGE = "No URI specified"
  4 + def dispatch
  5 + if client.needs_to_authorize?
  6 + raise Exception, "You need to authorize first."
  7 + end
  8 + options.path ||= OAuthClient.rcfile.alias_from_options(options)
  9 + perform_request
  10 + end
  11 +
  12 + def perform_request
  13 + client.perform_request_from_options(options) { |response|
  14 + response.read_body { |chunk| Stream.print chunk }
  15 + }
  16 + rescue URI::InvalidURIError
  17 + Stream.puts NO_URI_MESSAGE
  18 + end
  19 + end
  20 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl/stream.rb 0 → 100755
... ... @@ -0,0 +1,157 @@
  1 +module Twurl
  2 + class Stream
  3 +
  4 + SUPPORTED_COMMANDS = %w(authorize accounts alias set)
  5 + DEFAULT_COMMAND = 'request'
  6 + PATH_PATTERN = /^\/\w+/
  7 + PROTOCOL_PATTERN = /^\w+:\/\//
  8 + README = File.dirname(__FILE__) + '/../../README'
  9 + @output ||= STDOUT
  10 + class NoPathFound < Exception
  11 + end
  12 +
  13 + class << self
  14 + attr_accessor :output
  15 +
  16 + def run(tags, config_file_path, proxy=nil)
  17 + begin
  18 + @@file_path = config_file_path
  19 + Twurl.options = Options.new
  20 + Twurl.options.command = 'request' # Not necessary anymore
  21 + Twurl.options.data = {"track"=>tags}
  22 +# Twurl.options.proxy = 'http://161.148.1.167:312' # Use for production mode at SERPRO
  23 + if !proxy.nil?
  24 + Twurl.options.proxy = proxy
  25 + end
  26 + Twurl.options.trace = false
  27 + Twurl.options.headers = {}
  28 + Twurl.options.subcommands=[]
  29 + Twurl.options.upload = {}
  30 + Twurl.options.upload['file'] = []
  31 + Twurl.options.path="/1.1/statuses/filter.json"
  32 + Twurl.options.host="stream.twitter.com"
  33 + Twurl.options.read_timeout= 0
  34 + rescue NoPathFound => e
  35 + exit
  36 + end
  37 + dispatch(Twurl.options)
  38 + end
  39 +
  40 + def file_path
  41 + @@file_path
  42 + end
  43 +
  44 + def dispatch(options)
  45 + client = OAuthClient.load_from_options(options)
  46 + controller = RequestController
  47 + controller.dispatch(client, options)
  48 + rescue Twurl::Exception => exception
  49 + abort(exception.message)
  50 + end
  51 +
  52 + def output
  53 + if Twurl.options && Twurl.options.output
  54 + Twurl.options.output
  55 + else
  56 + @output
  57 + end
  58 + end
  59 +
  60 + def print(*args, &block)
  61 + output.print(*args, &block)
  62 + output.flush if output.respond_to?(:flush)
  63 + end
  64 +
  65 + def puts(*args, &block)
  66 + output.puts(*args, &block)
  67 + output.flush if output.respond_to?(:flush)
  68 + end
  69 +
  70 + def prompt_for(label)
  71 + system "stty -echo"
  72 + CLI.print "#{label}: "
  73 + result = STDIN.gets.chomp
  74 + CLI.puts
  75 + result
  76 + rescue Interrupt
  77 + exit
  78 + ensure
  79 + system "stty echo"
  80 + end
  81 +
  82 + private
  83 + def extract_command!(arguments)
  84 + if SUPPORTED_COMMANDS.include?(arguments.first)
  85 + arguments.shift
  86 + else
  87 + DEFAULT_COMMAND
  88 + end
  89 + end
  90 +
  91 + def extract_path!(arguments)
  92 + path = nil
  93 + arguments.each_with_index do |argument, index|
  94 + if argument[PATH_PATTERN]
  95 + path_with_params = arguments.slice!(index)
  96 + path, params = path_with_params.split("?", 2)
  97 + if params
  98 + path += "?" + escape_params(params)
  99 + end
  100 + break
  101 + end
  102 + end
  103 + path
  104 + end
  105 +
  106 + def escape_params(params)
  107 + split_params = params.split("&").map do |param|
  108 + key, value = param.split('=', 2)
  109 + CGI::escape(key) + '=' + CGI::escape(value)
  110 + end
  111 + split_params.join("&")
  112 + end
  113 + end
  114 + end
  115 +
  116 +
  117 + class Options < OpenStruct
  118 + DEFAULT_REQUEST_METHOD = 'get'
  119 + DEFAULT_HOST = 'api.twitter.com'
  120 + DEFAULT_PROTOCOL = 'https'
  121 +
  122 + def oauth_client_options
  123 + OAuthClient::OAUTH_CLIENT_OPTIONS.inject({}) do |options, option|
  124 + options[option] = send(option)
  125 + options
  126 + end
  127 + end
  128 +
  129 + def base_url
  130 + "#{protocol}://#{host}"
  131 + end
  132 +
  133 + def ssl?
  134 + protocol == 'https'
  135 + end
  136 +
  137 + def debug_output_io
  138 + super || STDERR
  139 + end
  140 +
  141 + def request_method
  142 + super || (data.empty? ? DEFAULT_REQUEST_METHOD : 'post')
  143 + end
  144 +
  145 + def protocol
  146 + super || DEFAULT_PROTOCOL
  147 + end
  148 +
  149 + def host
  150 + super || DEFAULT_HOST
  151 + end
  152 +
  153 + def proxy
  154 + super || nil
  155 + end
  156 + end
  157 +end
... ...
plugins/community_hub/tweeter_stream/lib/twurl/version.rb 0 → 100755
... ... @@ -0,0 +1,17 @@
  1 +module Twurl
  2 + class Version
  3 + MAJOR = 0 unless defined? Twurl::Version::MAJOR
  4 + MINOR = 9 unless defined? Twurl::Version::MINOR
  5 + PATCH = 2 unless defined? Twurl::Version::PATCH
  6 + BETA = nil unless defined? Twurl::Version::BETA # Time.now.to_i.to_s
  7 +
  8 + class << self
  9 + # @return [String]
  10 + def to_s
  11 + [MAJOR, MINOR, PATCH, BETA].compact.join('.')
  12 + end
  13 + end
  14 + end
  15 +
  16 + VERSION = Version.to_s
  17 +end
... ...
plugins/community_hub/tweeter_stream/nbproject/project.properties 0 → 100755
... ... @@ -0,0 +1,9 @@
  1 +file.reference.twurl-bin=bin
  2 +file.reference.twurl-lib=lib
  3 +file.reference.twurl-test=test
  4 +lib.dir=${file.reference.twurl-lib}
  5 +main.file=
  6 +platform.active=Ruby
  7 +source.encoding=UTF-8
  8 +src.dir=${file.reference.twurl-bin}
  9 +test.src.dir=${file.reference.twurl-test}
... ...
plugins/community_hub/tweeter_stream/nbproject/project.xml 0 → 100755
... ... @@ -0,0 +1,16 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://www.netbeans.org/ns/project/1">
  3 + <type>org.netbeans.modules.ruby.rubyproject</type>
  4 + <configuration>
  5 + <data xmlns="http://www.netbeans.org/ns/ruby-project/1">
  6 + <name>twurl</name>
  7 + <source-roots>
  8 + <root id="src.dir"/>
  9 + <root id="lib.dir"/>
  10 + </source-roots>
  11 + <test-roots>
  12 + <root id="test.src.dir"/>
  13 + </test-roots>
  14 + </data>
  15 + </configuration>
  16 +</project>
... ...
plugins/community_hub/tweeter_stream/noosfero.rb 0 → 100755
... ... @@ -0,0 +1,4 @@
  1 +#!/usr/bin/env ruby
  2 +require File.dirname(__FILE__) + '/lib/twurl'
  3 +
  4 +Twurl::Stream.run('nba', '/root/.twurlrc')
... ...
plugins/community_hub/tweeter_stream/test/account_information_controller_test.rb 0 → 100755
... ... @@ -0,0 +1,61 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::AccountInformationController::DispatchWithNoAuthorizedAccountsTest < Minitest::Test
  4 + attr_reader :options, :client, :controller
  5 + def setup
  6 + @options = Twurl::Options.new
  7 + @client = Twurl::OAuthClient.load_new_client_from_options(options)
  8 + @controller = Twurl::AccountInformationController.new(client, options)
  9 + mock(Twurl::OAuthClient.rcfile).empty? { true }
  10 + end
  11 +
  12 + def test_message_indicates_when_no_accounts_are_authorized
  13 + mock(Twurl::CLI).puts(Twurl::AccountInformationController::NO_AUTHORIZED_ACCOUNTS_MESSAGE).times(1)
  14 +
  15 + controller.dispatch
  16 + end
  17 +end
  18 +
  19 +class Twurl::AccountInformationController::DispatchWithOneAuthorizedAccountTest < Minitest::Test
  20 + attr_reader :options, :client, :controller
  21 + def setup
  22 + @options = Twurl::Options.test_exemplar
  23 + @client = Twurl::OAuthClient.load_new_client_from_options(options)
  24 + mock(Twurl::OAuthClient.rcfile).save.times(1)
  25 + Twurl::OAuthClient.rcfile << client
  26 + @controller = Twurl::AccountInformationController.new(client, options)
  27 + end
  28 +
  29 + def test_authorized_account_is_displayed_and_marked_as_the_default
  30 + mock(Twurl::CLI).puts(client.username).times(1).ordered
  31 + mock(Twurl::CLI).puts(" #{client.consumer_key} (default)").times(1).ordered
  32 +
  33 + controller.dispatch
  34 + end
  35 +end
  36 +
  37 +class Twurl::AccountInformationController::DispatchWithOneUsernameThatHasAuthorizedMultipleAccountsTest < Minitest::Test
  38 + attr_reader :default_client_options, :default_client, :other_client_options, :other_client, :controller
  39 + def setup
  40 + @default_client_options = Twurl::Options.test_exemplar
  41 + @default_client = Twurl::OAuthClient.load_new_client_from_options(default_client_options)
  42 +
  43 + @other_client_options = Twurl::Options.test_exemplar
  44 + other_client_options.consumer_key = default_client_options.consumer_key.reverse
  45 + @other_client = Twurl::OAuthClient.load_new_client_from_options(other_client_options)
  46 + mock(Twurl::OAuthClient.rcfile).save.times(2)
  47 +
  48 + Twurl::OAuthClient.rcfile << default_client
  49 + Twurl::OAuthClient.rcfile << other_client
  50 +
  51 + @controller = Twurl::AccountInformationController.new(other_client, other_client_options)
  52 + end
  53 +
  54 + def test_authorized_account_is_displayed_and_marked_as_the_default
  55 + mock(Twurl::CLI).puts(default_client.username).times(1)
  56 + mock(Twurl::CLI).puts(" #{default_client.consumer_key} (default)").times(1)
  57 + mock(Twurl::CLI).puts(" #{other_client.consumer_key}").times(1)
  58 +
  59 + controller.dispatch
  60 + end
  61 +end
... ...
plugins/community_hub/tweeter_stream/test/alias_controller_test.rb 0 → 100755
... ... @@ -0,0 +1,53 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::AliasesController::DispatchTest < Minitest::Test
  4 + attr_reader :options, :client
  5 + def setup
  6 + @options = Twurl::Options.test_exemplar
  7 + @client = Twurl::OAuthClient.test_exemplar
  8 +
  9 + # Clean slate
  10 + if Twurl::OAuthClient.rcfile.aliases
  11 + Twurl::OAuthClient.rcfile.aliases.clear
  12 + end
  13 +
  14 + stub(Twurl::OAuthClient.rcfile).save
  15 + end
  16 +
  17 + def test_when_no_subcommands_are_provided_and_no_aliases_exist_nothing_is_displayed
  18 + assert options.subcommands.empty?
  19 + mock(Twurl::CLI).puts(Twurl::AliasesController::NO_ALIASES_MESSAGE).times(1)
  20 +
  21 + controller = Twurl::AliasesController.new(client, options)
  22 + controller.dispatch
  23 + end
  24 +
  25 + def test_when_no_subcommands_are_provided_and_aliases_exist_they_are_displayed
  26 + assert options.subcommands.empty?
  27 +
  28 + Twurl::OAuthClient.rcfile.alias('h', '/1.1/statuses/home_timeline.json')
  29 + mock(Twurl::CLI).puts("h: /1.1/statuses/home_timeline.json").times(1)
  30 +
  31 + controller = Twurl::AliasesController.new(client, options)
  32 + controller.dispatch
  33 + end
  34 +
  35 + def test_when_alias_and_value_are_provided_they_are_added
  36 + options.subcommands = ['h']
  37 + options.path = '/1.1/statuses/home_timeline.json'
  38 + mock(Twurl::OAuthClient.rcfile).alias('h', '/1.1/statuses/home_timeline.json').times(1)
  39 +
  40 + controller = Twurl::AliasesController.new(client, options)
  41 + controller.dispatch
  42 + end
  43 +
  44 + def test_when_no_path_is_provided_nothing_happens
  45 + options.subcommands = ['a']
  46 + assert_nil options.path
  47 +
  48 + mock(Twurl::CLI).puts(Twurl::AliasesController::NO_PATH_PROVIDED_MESSAGE).times(1)
  49 +
  50 + controller = Twurl::AliasesController.new(client, options)
  51 + controller.dispatch
  52 + end
  53 +end
... ...
plugins/community_hub/tweeter_stream/test/authorization_controller_test.rb 0 → 100755
... ... @@ -0,0 +1,30 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::AuthorizationController::DispatchTest < Minitest::Test
  4 + attr_reader :options, :client, :controller
  5 + def setup
  6 + @options = Twurl::Options.new
  7 + @client = Twurl::OAuthClient.load_new_client_from_options(options)
  8 + @controller = Twurl::AuthorizationController.new(client, options)
  9 + end
  10 +
  11 + def test_successful_authentication_saves_retrieved_access_token
  12 + mock(client).exchange_credentials_for_access_token.times(1)
  13 + mock(client).save.times(1)
  14 + mock(controller).raise(Twurl::Exception, Twurl::AuthorizationController::AUTHORIZATION_FAILED_MESSAGE).never
  15 + mock(Twurl::CLI).puts(Twurl::AuthorizationController::AUTHORIZATION_SUCCEEDED_MESSAGE).times(1)
  16 +
  17 + controller.dispatch
  18 + end
  19 +
  20 + module ErrorCases
  21 + def test_failed_authorization_does_not_save_client
  22 + mock(client).exchange_credentials_for_access_token { raise OAuth::Unauthorized }
  23 + mock(client).save.never
  24 + mock(controller).raise(Twurl::Exception, Twurl::AuthorizationController::AUTHORIZATION_FAILED_MESSAGE).times(1)
  25 +
  26 + controller.dispatch
  27 + end
  28 + end
  29 + include ErrorCases
  30 +end
... ...
plugins/community_hub/tweeter_stream/test/cli_options_test.rb 0 → 100755
... ... @@ -0,0 +1,23 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::Options::Test < Minitest::Test
  4 + attr_reader :options
  5 + def setup
  6 + @options = Twurl::Options.new
  7 + end
  8 +
  9 + def test_base_url_is_built_from_protocol_and_host
  10 + options.protocol = 'http'
  11 + options.host = 'api.twitter.com'
  12 +
  13 + assert_equal 'http://api.twitter.com', options.base_url
  14 + end
  15 +
  16 + def test_ssl_is_enabled_if_the_protocol_is_https
  17 + options.protocol = 'http'
  18 + assert !options.ssl?
  19 +
  20 + options.protocol = 'https'
  21 + assert options.ssl?
  22 + end
  23 +end
... ...
plugins/community_hub/tweeter_stream/test/cli_test.rb 0 → 100755
... ... @@ -0,0 +1,192 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::CLI::OptionParsingTest < Minitest::Test
  4 + TEST_PATH = '/1.1/url/does/not/matter.json'
  5 +
  6 + module CommandParsingTests
  7 + def test_no_command_specified_falls_to_default_command
  8 + options = Twurl::CLI.parse_options([TEST_PATH])
  9 + assert_equal Twurl::CLI::DEFAULT_COMMAND, options.command
  10 + end
  11 +
  12 + def test_supported_command_specified_extracts_the_command
  13 + expected_command = Twurl::CLI::SUPPORTED_COMMANDS.first
  14 + options = Twurl::CLI.parse_options([expected_command])
  15 + assert_equal expected_command, options.command
  16 + end
  17 +
  18 + def test_unsupported_command_specified_sets_default_command
  19 + unsupported_command = 'unsupported'
  20 + options = Twurl::CLI.parse_options([TEST_PATH, unsupported_command])
  21 + assert_equal Twurl::CLI::DEFAULT_COMMAND, options.command
  22 + end
  23 + end
  24 + include CommandParsingTests
  25 +
  26 + module PathParsingTests
  27 + def test_missing_path_throws_no_path_found
  28 + stub(Twurl::CLI).puts
  29 + assert_raises Twurl::CLI::NoPathFound do
  30 + Twurl::CLI.parse_options([])
  31 + end
  32 + end
  33 +
  34 + def test_uri_params_are_encoded
  35 + options = Twurl::CLI.parse_options(["/1.1/url?baz=bamf:rofl"])
  36 + assert_equal options.path, "/1.1/url?baz=bamf%3Arofl"
  37 + end
  38 + end
  39 + include PathParsingTests
  40 +
  41 + module RequestMethodParsingTests
  42 + def test_request_method_is_default_if_unspecified
  43 + options = Twurl::CLI.parse_options([TEST_PATH])
  44 + assert_equal Twurl::Options::DEFAULT_REQUEST_METHOD, options.request_method
  45 + end
  46 +
  47 + def test_specifying_a_request_method_extracts_and_normalizes_request_method
  48 + variations = [%w[-X put], %w[-X PUT], %w[--request-method PUT], %w[--request-method put]]
  49 + variations.each do |option_variation|
  50 + order_variant_1 = [option_variation, TEST_PATH].flatten
  51 + order_variant_2 = [TEST_PATH, option_variation].flatten
  52 + [order_variant_1, order_variant_2].each do |args|
  53 + options = Twurl::CLI.parse_options(args)
  54 + assert_equal 'put', options.request_method
  55 + end
  56 + end
  57 + end
  58 +
  59 + def test_specifying_unsupported_request_method_returns_an_error
  60 + Twurl::CLI.parse_options([TEST_PATH, '-X', 'UNSUPPORTED'])
  61 + end
  62 + end
  63 + include RequestMethodParsingTests
  64 +
  65 + module OAuthClientOptionParsingTests
  66 + def test_extracting_the_consumer_key
  67 + mock(Twurl::CLI).prompt_for('Consumer key').never
  68 +
  69 + options = Twurl::CLI.parse_options([TEST_PATH, '-c', 'the-key'])
  70 + assert_equal 'the-key', options.consumer_key
  71 + end
  72 +
  73 + def test_consumer_key_option_with_no_value_prompts_user_for_value
  74 + mock(Twurl::CLI).prompt_for('Consumer key').times(1) { 'inputted-key'}
  75 + options = Twurl::CLI.parse_options([TEST_PATH, '-c'])
  76 + assert_equal 'inputted-key', options.consumer_key
  77 + end
  78 + end
  79 + include OAuthClientOptionParsingTests
  80 +
  81 + module DataParsingTests
  82 + def test_extracting_a_single_key_value_pair
  83 + options = Twurl::CLI.parse_options([TEST_PATH, '-d', 'key=value'])
  84 + assert_equal({'key' => 'value'}, options.data)
  85 +
  86 + options = Twurl::CLI.parse_options([TEST_PATH, '--data', 'key=value'])
  87 + assert_equal({'key' => 'value'}, options.data)
  88 + end
  89 +
  90 + def test_passing_data_and_no_explicit_request_method_defaults_request_method_to_post
  91 + options = Twurl::CLI.parse_options([TEST_PATH, '-d', 'key=value'])
  92 + assert_equal 'post', options.request_method
  93 + end
  94 +
  95 + def test_passing_data_and_an_explicit_request_method_uses_the_specified_method
  96 + options = Twurl::CLI.parse_options([TEST_PATH, '-d', 'key=value', '-X', 'DELETE'])
  97 + assert_equal({'key' => 'value'}, options.data)
  98 + assert_equal 'delete', options.request_method
  99 + end
  100 +
  101 + def test_multiple_pairs_when_option_is_specified_multiple_times_on_command_line_collects_all
  102 + options = Twurl::CLI.parse_options([TEST_PATH, '-d', 'key=value', '-d', 'another=pair'])
  103 + assert_equal({'key' => 'value', 'another' => 'pair'}, options.data)
  104 + end
  105 +
  106 + def test_multiple_pairs_separated_by_ampersand_are_all_captured
  107 + options = Twurl::CLI.parse_options([TEST_PATH, '-d', 'key=value&another=pair'])
  108 + assert_equal({'key' => 'value', 'another' => 'pair'}, options.data)
  109 + end
  110 +
  111 + def test_extracting_an_empty_key_value_pair
  112 + options = Twurl::CLI.parse_options([TEST_PATH, '-d', 'key='])
  113 + assert_equal({'key' => ''}, options.data)
  114 +
  115 + options = Twurl::CLI.parse_options([TEST_PATH, '--data', 'key='])
  116 + assert_equal({'key' => ''}, options.data)
  117 + end
  118 + end
  119 + include DataParsingTests
  120 +
  121 + module HeaderParsingTests
  122 + def test_extracting_a_single_header
  123 + options = Twurl::CLI.parse_options([TEST_PATH, '-A', 'Key: Value'])
  124 + assert_equal({'Key' => 'Value'}, options.headers)
  125 +
  126 + options = Twurl::CLI.parse_options([TEST_PATH, '--header', 'Key: Value'])
  127 + assert_equal({'Key' => 'Value'}, options.headers)
  128 + end
  129 +
  130 + def test_multiple_headers_when_option_is_specified_multiple_times_on_command_line_collects_all
  131 + options = Twurl::CLI.parse_options([TEST_PATH, '-A', 'Key: Value', '-A', 'Another: Pair'])
  132 + assert_equal({'Key' => 'Value', 'Another' => 'Pair'}, options.headers)
  133 + end
  134 + end
  135 + include HeaderParsingTests
  136 +
  137 + module SSLDisablingTests
  138 + def test_ssl_is_on_by_default
  139 + options = Twurl::CLI.parse_options([TEST_PATH])
  140 + assert options.ssl?
  141 + end
  142 +
  143 + def test_passing_no_ssl_option_disables_ssl
  144 + ['-U', '--no-ssl'].each do |switch|
  145 + options = Twurl::CLI.parse_options([TEST_PATH, switch])
  146 + assert !options.ssl?
  147 + end
  148 + end
  149 + end
  150 + include SSLDisablingTests
  151 +
  152 + module HostOptionTests
  153 + def test_not_specifying_host_sets_it_to_the_default
  154 + options = Twurl::CLI.parse_options([TEST_PATH])
  155 + assert_equal Twurl::Options::DEFAULT_HOST, options.host
  156 + end
  157 +
  158 + def test_setting_host_updates_to_requested_value
  159 + custom_host = 'localhost:3000'
  160 + assert Twurl::Options::DEFAULT_HOST != custom_host
  161 +
  162 + [[TEST_PATH, '-H', custom_host], [TEST_PATH, '--host', custom_host]].each do |option_combination|
  163 + options = Twurl::CLI.parse_options(option_combination)
  164 + assert_equal custom_host, options.host
  165 + end
  166 + end
  167 +
  168 + def test_protocol_is_stripped_from_host
  169 + custom_host = 'localhost:3000'
  170 + options = Twurl::CLI.parse_options([TEST_PATH, '-H', "https://"+custom_host])
  171 + assert_equal custom_host, options.host
  172 + end
  173 + end
  174 + include HostOptionTests
  175 +
  176 + module ProxyOptionTests
  177 + def test_not_specifying_proxy_sets_it_to_nil
  178 + options = Twurl::CLI.parse_options([TEST_PATH])
  179 + assert_equal nil, options.proxy
  180 + end
  181 +
  182 + def test_setting_proxy_updates_to_requested_value
  183 + custom_proxy = 'localhost:80'
  184 +
  185 + [[TEST_PATH, '-P', custom_proxy], [TEST_PATH, '--proxy', custom_proxy]].each do |option_combination|
  186 + options = Twurl::CLI.parse_options(option_combination)
  187 + assert_equal custom_proxy, options.proxy
  188 + end
  189 + end
  190 + end
  191 + include ProxyOptionTests
  192 +end
... ...
plugins/community_hub/tweeter_stream/test/configuration_controller_test.rb 0 → 100755
... ... @@ -0,0 +1,44 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::ConfigurationController::DispatchTest < Minitest::Test
  4 + def test_error_message_is_displayed_if_setting_is_unrecognized
  5 + options = Twurl::Options.test_exemplar
  6 + client = Twurl::OAuthClient.test_exemplar
  7 +
  8 + options.subcommands = ['unrecognized', 'value']
  9 +
  10 + mock(Twurl::CLI).puts(Twurl::ConfigurationController::UNRECOGNIZED_SETTING_MESSAGE % 'unrecognized').times(1)
  11 + mock(Twurl::OAuthClient.rcfile).save.times(0)
  12 +
  13 + controller = Twurl::ConfigurationController.new(client, options)
  14 + controller.dispatch
  15 + end
  16 +end
  17 +
  18 +class Twurl::ConfigurationController::DispatchDefaultSettingTest < Minitest::Test
  19 + def test_setting_default_profile_just_by_username
  20 + options = Twurl::Options.test_exemplar
  21 + client = Twurl::OAuthClient.test_exemplar
  22 +
  23 + options.subcommands = ['default', client.username]
  24 + mock(Twurl::OAuthClient).load_client_for_username(client.username).times(1) { client }
  25 + mock(Twurl::OAuthClient.rcfile).default_profile = client
  26 + mock(Twurl::OAuthClient.rcfile).save.times(1)
  27 +
  28 + controller = Twurl::ConfigurationController.new(client, options)
  29 + controller.dispatch
  30 + end
  31 +
  32 + def test_setting_default_profile_by_username_and_consumer_key
  33 + options = Twurl::Options.test_exemplar
  34 + client = Twurl::OAuthClient.test_exemplar
  35 +
  36 + options.subcommands = ['default', client.username, client.consumer_key]
  37 + mock(Twurl::OAuthClient).load_client_for_username_and_consumer_key(client.username, client.consumer_key).times(1) { client }
  38 + mock(Twurl::OAuthClient.rcfile).default_profile = client
  39 + mock(Twurl::OAuthClient.rcfile).save.times(1)
  40 +
  41 + controller = Twurl::ConfigurationController.new(client, options)
  42 + controller.dispatch
  43 + end
  44 +end
... ...
plugins/community_hub/tweeter_stream/test/oauth_client_test.rb 0 → 100755
... ... @@ -0,0 +1,165 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::OAuthClient::AbstractOAuthClientTest < Minitest::Test
  4 + attr_reader :client, :options
  5 + def setup
  6 + Twurl::OAuthClient.instance_variable_set(:@rcfile, nil)
  7 +
  8 + @options = Twurl::Options.test_exemplar
  9 + @client = Twurl::OAuthClient.test_exemplar
  10 + options.base_url = 'api.twitter.com'
  11 + options.request_method = 'get'
  12 + options.path = '/path/does/not/matter.json'
  13 + options.data = {}
  14 + options.headers = {}
  15 +
  16 + Twurl.options = options
  17 + end
  18 +
  19 + def teardown
  20 + super
  21 + Twurl.options = Twurl::Options.new
  22 + # Make sure we don't do any disk IO in these tests
  23 + assert !File.exists?(Twurl::RCFile.file_path)
  24 + end
  25 +
  26 + def test_nothing
  27 + # Appeasing test/unit
  28 + end
  29 +end
  30 +
  31 +class Twurl::OAuthClient::BasicRCFileLoadingTest < Twurl::OAuthClient::AbstractOAuthClientTest
  32 + def test_rcfile_is_memoized
  33 + mock.proxy(Twurl::RCFile).new.times(1)
  34 +
  35 + Twurl::OAuthClient.rcfile
  36 + Twurl::OAuthClient.rcfile
  37 + end
  38 +
  39 + def test_forced_reloading
  40 + mock.proxy(Twurl::RCFile).new.times(2)
  41 +
  42 + Twurl::OAuthClient.rcfile
  43 + Twurl::OAuthClient.rcfile(:reload)
  44 + Twurl::OAuthClient.rcfile
  45 + end
  46 +end
  47 +
  48 +class Twurl::OAuthClient::ClientLoadingFromOptionsTest < Twurl::OAuthClient::AbstractOAuthClientTest
  49 + def test_if_username_is_supplied_and_no_profile_exists_for_username_then_new_client_is_created
  50 + mock(Twurl::OAuthClient).load_client_for_username(options.username).never
  51 + mock(Twurl::OAuthClient).load_new_client_from_options(options).times(1)
  52 + mock(Twurl::OAuthClient).load_default_client.never
  53 +
  54 + Twurl::OAuthClient.load_from_options(options)
  55 + end
  56 +
  57 + def test_if_username_is_supplied_and_profile_exists_for_username_then_client_is_loaded
  58 + mock(Twurl::OAuthClient.rcfile).save.times(1)
  59 + Twurl::OAuthClient.rcfile << client
  60 +
  61 + mock(Twurl::OAuthClient).load_client_for_username_and_consumer_key(options.username, options.consumer_key).times(1)
  62 + mock(Twurl::OAuthClient).load_new_client_from_options(options).never
  63 + mock(Twurl::OAuthClient).load_default_client.never
  64 +
  65 + Twurl::OAuthClient.load_from_options(options)
  66 + end
  67 +
  68 + def test_if_username_is_not_provided_then_the_default_client_is_loaded
  69 + options.username = nil
  70 +
  71 + mock(Twurl::OAuthClient).load_client_for_username(options.username).never
  72 + mock(Twurl::OAuthClient).load_new_client_from_options(options).never
  73 + mock(Twurl::OAuthClient).load_default_client.times(1)
  74 +
  75 + Twurl::OAuthClient.load_from_options(options)
  76 + end
  77 +end
  78 +
  79 +class Twurl::OAuthClient::ClientLoadingForUsernameTest < Twurl::OAuthClient::AbstractOAuthClientTest
  80 + def test_attempting_to_load_a_username_that_is_not_in_the_file_fails
  81 + assert_nil Twurl::OAuthClient.rcfile[client.username]
  82 +
  83 + assert_raises Twurl::Exception do
  84 + Twurl::OAuthClient.load_client_for_username_and_consumer_key(client.username, client.consumer_key)
  85 + end
  86 + end
  87 +
  88 + def test_loading_a_username_that_exists
  89 + mock(Twurl::OAuthClient.rcfile).save.times(1)
  90 +
  91 + Twurl::OAuthClient.rcfile << client
  92 +
  93 + client_from_file = Twurl::OAuthClient.load_client_for_username_and_consumer_key(client.username, client.consumer_key)
  94 + assert_equal client.to_hash, client_from_file.to_hash
  95 + end
  96 +end
  97 +
  98 +class Twurl::OAuthClient::DefaultClientLoadingTest < Twurl::OAuthClient::AbstractOAuthClientTest
  99 + def test_loading_default_client_when_there_is_none_fails
  100 + assert_nil Twurl::OAuthClient.rcfile.default_profile
  101 +
  102 + assert_raises Twurl::Exception do
  103 + Twurl::OAuthClient.load_default_client
  104 + end
  105 + end
  106 +
  107 + def test_loading_default_client_from_file
  108 + mock(Twurl::OAuthClient.rcfile).save.times(1)
  109 +
  110 + Twurl::OAuthClient.rcfile << client
  111 + assert_equal [client.username, client.consumer_key], Twurl::OAuthClient.rcfile.default_profile
  112 +
  113 + client_from_file = Twurl::OAuthClient.load_default_client
  114 +
  115 + assert_equal client.to_hash, client_from_file.to_hash
  116 + end
  117 +end
  118 +
  119 +class Twurl::OAuthClient::NewClientLoadingFromOptionsTest < Twurl::OAuthClient::AbstractOAuthClientTest
  120 + attr_reader :new_client
  121 + def setup
  122 + super
  123 + @new_client = Twurl::OAuthClient.load_new_client_from_options(options)
  124 + end
  125 +
  126 + def test_password_is_included
  127 + assert_equal options.password, new_client.password
  128 + end
  129 +
  130 + def test_oauth_options_are_passed_through
  131 + assert_equal client.to_hash, new_client.to_hash
  132 + end
  133 +end
  134 +
  135 +class Twurl::OAuthClient::PerformingRequestsFromOptionsTest < Twurl::OAuthClient::AbstractOAuthClientTest
  136 + def test_request_is_made_using_request_method_and_path_and_data_in_options
  137 + client = Twurl::OAuthClient.test_exemplar
  138 + mock(client.consumer.http).request(satisfy { |req|
  139 + req.is_a?(Net::HTTP::Get) && (req.path == options.path)
  140 + })
  141 +
  142 + client.perform_request_from_options(options)
  143 + end
  144 +end
  145 +
  146 +class Twurl::OAuthClient::CredentialsForAccessTokenExchangeTest < Twurl::OAuthClient::AbstractOAuthClientTest
  147 + def test_successful_exchange_parses_token_and_secret_from_response_body
  148 + parsed_response = {:oauth_token => "123456789",
  149 + :oauth_token_secret => "abcdefghi",
  150 + :user_id => "3191321",
  151 + :screen_name => "noradio",
  152 + :x_auth_expires => "0"}
  153 +
  154 + mock(client.consumer).
  155 + token_request(:post,
  156 + client.consumer.access_token_path,
  157 + nil,
  158 + {},
  159 + client.client_auth_parameters) { parsed_response }
  160 +
  161 + assert client.needs_to_authorize?
  162 + client.exchange_credentials_for_access_token
  163 + assert !client.needs_to_authorize?
  164 + end
  165 +end
... ...
plugins/community_hub/tweeter_stream/test/rcfile_test.rb 0 → 100755
... ... @@ -0,0 +1,147 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::RCFile::PathConstructionTest < Minitest::Test
  4 + def test_file_path_appends_file_to_directory
  5 + assert_equal File.join(Twurl::RCFile.directory, Twurl::RCFile::FILE), Twurl::RCFile.file_path
  6 + end
  7 +end
  8 +
  9 +class Twurl::RCFile::LoadingTest < Minitest::Test
  10 + def test_load_parses_and_loads_file_if_it_exists
  11 + mock(YAML).load_file(Twurl::RCFile.file_path).times(1)
  12 + mock(Twurl::RCFile).default_rcfile_structure.never
  13 +
  14 + Twurl::RCFile.load
  15 + end
  16 +
  17 + def test_load_returns_default_file_structure_if_file_does_not_exist
  18 + mock(YAML).load_file(Twurl::RCFile.file_path) { raise Errno::ENOENT }.times(1)
  19 + mock(Twurl::RCFile).default_rcfile_structure.times(1)
  20 +
  21 + Twurl::RCFile.load
  22 + end
  23 +end
  24 +
  25 +class Twurl::RCFile::InitializationTest < Minitest::Test
  26 + def test_initializing_when_the_file_does_not_exist_loads_default_rcfile_structure
  27 + mock(YAML).load_file(Twurl::RCFile.file_path) { raise Errno::ENOENT }.times(1)
  28 +
  29 + rcfile = Twurl::RCFile.new
  30 + assert_equal Twurl::RCFile.default_rcfile_structure, rcfile.data
  31 + end
  32 +
  33 + def test_initializing_when_the_file_does_exists_loads_content_of_file
  34 + mock_content_of_rcfile = {'this data' => 'does not matter'}
  35 + mock(YAML).load_file(Twurl::RCFile.file_path) { mock_content_of_rcfile }.times(1)
  36 + mock(Twurl::RCFile).default_rcfile_structure.never
  37 +
  38 + rcfile = Twurl::RCFile.new
  39 + assert_equal mock_content_of_rcfile, rcfile.data
  40 + end
  41 +end
  42 +
  43 +class Twurl::RCFile::DefaultProfileFromDefaultRCFileTest < Minitest::Test
  44 + attr_reader :rcfile
  45 + def setup
  46 + mock(YAML).load_file(Twurl::RCFile.file_path) { raise Errno::ENOENT }.times(1)
  47 + mock.proxy(Twurl::RCFile).default_rcfile_structure.times(any_times)
  48 +
  49 + @rcfile = Twurl::RCFile.new
  50 + end
  51 +
  52 + def test_default_rcfile_structure_has_no_default_profile
  53 + assert_nil rcfile.default_profile
  54 + end
  55 +
  56 + def test_rcfile_is_considered_empty_at_first
  57 + assert rcfile.empty?
  58 + end
  59 +
  60 + def test_setting_default_profile
  61 + options = Twurl::Options.test_exemplar
  62 +
  63 + client = Twurl::OAuthClient.load_new_client_from_options(options)
  64 + rcfile.default_profile = client
  65 + assert_equal [options.username, options.consumer_key], rcfile.default_profile
  66 + end
  67 +end
  68 +
  69 +class Twurl::RCFile::UpdatingTest < Minitest::Test
  70 + attr_reader :rcfile
  71 + def setup
  72 + mock(YAML).load_file(Twurl::RCFile.file_path) { raise Errno::ENOENT }.times(1)
  73 +
  74 + @rcfile = Twurl::RCFile.new
  75 + assert rcfile.profiles.empty?
  76 + assert_nil rcfile.default_profile
  77 + mock(rcfile).save.times(any_times)
  78 + end
  79 +
  80 + def test_adding_the_first_client_sets_it_as_default_profile
  81 + client = Twurl::OAuthClient.test_exemplar
  82 +
  83 + rcfile << client
  84 + assert_equal [client.username, client.consumer_key], rcfile.default_profile
  85 + assert rcfile.has_oauth_profile_for_username_with_consumer_key?(client.username, client.consumer_key)
  86 + assert_equal({client.username => {client.consumer_key => client.to_hash}}, rcfile.profiles)
  87 + end
  88 +
  89 + def test_adding_additional_clients_does_not_change_default_profile
  90 + first_client = Twurl::OAuthClient.test_exemplar
  91 +
  92 + rcfile << first_client
  93 + assert_equal [first_client.username, first_client.consumer_key], rcfile.default_profile
  94 + assert rcfile.has_oauth_profile_for_username_with_consumer_key?(first_client.username, first_client.consumer_key)
  95 +
  96 + additional_client = Twurl::OAuthClient.test_exemplar(:username => 'additional_exemplar_username')
  97 +
  98 + rcfile << additional_client
  99 + assert_equal [first_client.username, first_client.consumer_key], rcfile.default_profile
  100 + assert rcfile.has_oauth_profile_for_username_with_consumer_key?(additional_client.username, additional_client.consumer_key)
  101 +
  102 + expected_profiles = {
  103 + first_client.username => {first_client.consumer_key => first_client.to_hash},
  104 + additional_client.username => {additional_client.consumer_key => additional_client.to_hash}
  105 + }
  106 +
  107 + assert_equal expected_profiles, rcfile.profiles
  108 + end
  109 +end
  110 +
  111 +class Twurl::RCFile::SavingTest < Minitest::Test
  112 + attr_reader :rcfile
  113 + def setup
  114 + delete_rcfile
  115 + assert !rcfile_exists?
  116 + @rcfile = Twurl::RCFile.new
  117 + assert !rcfile_exists?
  118 + end
  119 +
  120 + def teardown
  121 + super
  122 + delete_rcfile
  123 + end
  124 +
  125 + def test_save_writes_profiles_to_disk
  126 + client = Twurl::OAuthClient.test_exemplar
  127 + rcfile << client
  128 + assert rcfile_exists?
  129 + end
  130 +
  131 + def test_file_is_not_world_readable
  132 + client = Twurl::OAuthClient.test_exemplar
  133 + rcfile << client
  134 + assert_equal 33152, File.stat(Twurl::RCFile.file_path).mode
  135 + end
  136 +
  137 + private
  138 + def rcfile_exists?
  139 + File.exists?(Twurl::RCFile.file_path)
  140 + end
  141 +
  142 + def delete_rcfile
  143 + File.unlink(Twurl::RCFile.file_path)
  144 + rescue Errno::ENOENT
  145 + # Do nothing
  146 + end
  147 +end
... ...
plugins/community_hub/tweeter_stream/test/request_controller_test.rb 0 → 100755
... ... @@ -0,0 +1,58 @@
  1 +require File.dirname(__FILE__) + '/test_helper'
  2 +
  3 +class Twurl::RequestController::AbstractTestCase < Minitest::Test
  4 + attr_reader :options, :client, :controller
  5 + def setup
  6 + Twurl::CLI.output = StringIO.new
  7 + @options = Twurl::Options.test_exemplar
  8 + @client = Twurl::OAuthClient.test_exemplar
  9 + @controller = Twurl::RequestController.new(client, options)
  10 + end
  11 +
  12 + def teardown
  13 + super
  14 + Twurl::CLI.output = STDOUT
  15 + end
  16 +
  17 + def test_nothing
  18 + # Appeasing test/unit
  19 + end
  20 +end
  21 +
  22 +class Twurl::RequestController::DispatchTest < Twurl::RequestController::AbstractTestCase
  23 + def test_request_will_be_made_if_client_is_authorized
  24 + mock(client).needs_to_authorize? { false }.times(1)
  25 + mock(controller).perform_request.times(1)
  26 +
  27 + controller.dispatch
  28 + end
  29 +
  30 + def test_request_will_not_be_made_if_client_is_not_authorized
  31 + mock(client).needs_to_authorize? { true }.times(1)
  32 + mock(controller).perform_request.never
  33 +
  34 + assert_raises Twurl::Exception do
  35 + controller.dispatch
  36 + end
  37 + end
  38 +end
  39 +
  40 +class Twurl::RequestController::RequestTest < Twurl::RequestController::AbstractTestCase
  41 + def test_request_response_is_written_to_output
  42 + expected_body = 'this is a fake response body'
  43 + response = Object.new
  44 + mock(response).read_body { |block| block.call expected_body }
  45 + mock(client).perform_request_from_options(options).times(1) { |options, block| block.call(response) }
  46 +
  47 + controller.perform_request
  48 +
  49 + assert_equal expected_body, Twurl::CLI.output.string
  50 + end
  51 +
  52 + def test_invalid_or_unspecified_urls_report_error
  53 + mock(Twurl::CLI).puts(Twurl::RequestController::NO_URI_MESSAGE).times(1)
  54 + mock(client).perform_request_from_options(options).times(1) { raise URI::InvalidURIError }
  55 +
  56 + controller.perform_request
  57 + end
  58 +end
... ...
plugins/community_hub/tweeter_stream/test/test_helper.rb 0 → 100755
... ... @@ -0,0 +1,44 @@
  1 +require 'simplecov'
  2 +require 'coveralls'
  3 +
  4 +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
  5 + SimpleCov::Formatter::HTMLFormatter,
  6 + Coveralls::SimpleCov::Formatter
  7 +]
  8 +SimpleCov.start
  9 +
  10 +require 'twurl'
  11 +require 'minitest/autorun'
  12 +require 'rr'
  13 +
  14 +Twurl::RCFile.directory = ENV['TMPDIR']
  15 +
  16 +module Twurl
  17 + class Options
  18 + class << self
  19 + def test_exemplar
  20 + options = new
  21 + options.username = 'exemplar_user_name'
  22 + options.password = 'secret'
  23 + options.consumer_key = '123456789'
  24 + options.consumer_secret = '987654321'
  25 + options.subcommands = []
  26 + options
  27 + end
  28 + end
  29 + end
  30 +
  31 + class OAuthClient
  32 + class << self
  33 + def test_exemplar(overrides = {})
  34 + options = Twurl::Options.test_exemplar
  35 +
  36 + overrides.each do |attribute, value|
  37 + options.send("#{attribute}=", value)
  38 + end
  39 +
  40 + load_new_client_from_options(options)
  41 + end
  42 + end
  43 + end
  44 +end
... ...
plugins/community_hub/tweeter_stream/twurl.gemspec 0 → 100755
... ... @@ -0,0 +1,25 @@
  1 +# coding: utf-8
  2 +lib = File.expand_path('../lib', __FILE__)
  3 +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
  4 +require 'twurl/version'
  5 +
  6 +Gem::Specification.new do |spec|
  7 + spec.add_dependency 'oauth', '~> 0.4'
  8 + spec.add_development_dependency 'bundler', '~> 1.0'
  9 + spec.authors = ["Marcel Molina", "Erik Michaels-Ober"]
  10 + spec.description = %q{Curl for the Twitter API}
  11 + spec.email = ['marcel@twitter.com']
  12 + spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
  13 + spec.extra_rdoc_files = %w(COPYING INSTALL README)
  14 + spec.files = `git ls-files`.split("\n")
  15 + spec.homepage = 'http://github.com/twitter/twurl'
  16 + spec.licenses = ['MIT']
  17 + spec.name = 'twurl'
  18 + spec.rdoc_options = ['--title', 'twurl -- OAuth-enabled curl for the Twitter API', '--main', 'README', '--line-numbers', '--inline-source']
  19 + spec.require_paths = ['lib']
  20 + spec.required_rubygems_version = '>= 1.3.5'
  21 + spec.rubyforge_project = 'twurl'
  22 + spec.summary = spec.description
  23 + spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
  24 + spec.version = Twurl::Version
  25 +end
... ...