powncer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +80 -0
- data/lib/powncer.rb +20 -0
- data/lib/powncer/authentication.rb +84 -0
- data/lib/powncer/base.rb +103 -0
- data/lib/powncer/connection.rb +33 -0
- data/lib/powncer/event.rb +40 -0
- data/lib/powncer/ext.rb +58 -0
- data/lib/powncer/link.rb +28 -0
- data/lib/powncer/media.rb +26 -0
- data/lib/powncer/note.rb +101 -0
- data/lib/powncer/user.rb +64 -0
- data/lib/powncer/version.rb +16 -0
- data/test/examples/authenticated_examples.rb +953 -0
- data/test/examples/basic_examples.rb +462 -0
- data/test/test_helper.rb +34 -0
- data/test/unit/1_1_TESTS +21 -0
- data/test/unit/authentication_test.rb +28 -0
- data/test/unit/base_test.rb +13 -0
- data/test/unit/connection_test.rb +12 -0
- data/test/unit/event_test.rb +44 -0
- data/test/unit/link_test.rb +48 -0
- data/test/unit/media_test.rb +22 -0
- data/test/unit/note_test.rb +131 -0
- data/test/unit/user_test.rb +45 -0
- metadata +85 -0
data/Rakefile
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require File.join(File.dirname(__FILE__), 'lib', 'powncer', 'version')
|
7
|
+
|
8
|
+
def library_root
|
9
|
+
File.dirname(__FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Run tests'
|
13
|
+
task :default => :test
|
14
|
+
|
15
|
+
Rake::TestTask.new('test') do |t|
|
16
|
+
t.libs << 'test'
|
17
|
+
t.pattern = 'test/*/*_test.rb'
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Check code to test ratio'
|
21
|
+
task :stats do
|
22
|
+
library_files = FileList["#{library_root}/lib/**/*.rb"]
|
23
|
+
test_files = FileList["#{library_root}/test/**/*_test.rb"]
|
24
|
+
count_code_lines = Proc.new do |lines|
|
25
|
+
lines.inject(0) do |code_lines, line|
|
26
|
+
next code_lines if [/^\s*$/, /^\s*#/].any? {|non_code_line| non_code_line === line}
|
27
|
+
code_lines + 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
count_code_lines_for_files = Proc.new do |files|
|
32
|
+
files.inject(0) {|code_lines, file| code_lines + count_code_lines[IO.read(file)]}
|
33
|
+
end
|
34
|
+
|
35
|
+
library_code_lines = count_code_lines_for_files[library_files]
|
36
|
+
test_code_lines = count_code_lines_for_files[test_files]
|
37
|
+
ratio = Proc.new { sprintf('%.2f', test_code_lines.to_f / library_code_lines)}
|
38
|
+
|
39
|
+
puts "Code LOC: #{library_code_lines} Test LOC: #{test_code_lines} Code to Test Ratio: 1:#{ratio.call}"
|
40
|
+
end
|
41
|
+
|
42
|
+
namespace :dist do
|
43
|
+
spec = Gem::Specification.new do |s|
|
44
|
+
s.name = "powncer"
|
45
|
+
s.version = Gem::Version.new(Powncer::Version::VERSION)
|
46
|
+
s.author = "Jae Hess"
|
47
|
+
s.email = "jae.hess@gmail.com"
|
48
|
+
s.homepage = "http://powncer.rubyforge.org"
|
49
|
+
s.platform = Gem::Platform::RUBY
|
50
|
+
s.summary = "Powncer is a Ruby library to the Pownce REST API"
|
51
|
+
s.files = FileList['Rakefile', 'lib/**/*.rb']
|
52
|
+
s.require_path = "lib"
|
53
|
+
s.test_files = Dir['test/**/*']
|
54
|
+
s.has_rdoc = true
|
55
|
+
s.rubyforge_project = 'powncer'
|
56
|
+
s.add_dependency 'json'
|
57
|
+
end
|
58
|
+
|
59
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
60
|
+
pkg.need_tar = true
|
61
|
+
end
|
62
|
+
|
63
|
+
package_name = lambda {|specification| File.join('pkg', "#{specification.name}-#{specification.version}")}
|
64
|
+
|
65
|
+
desc 'Push a release to rubyforge'
|
66
|
+
task :release => ['dist:clobber_package', :package] do
|
67
|
+
require 'rubyforge'
|
68
|
+
package = package_name[spec]
|
69
|
+
|
70
|
+
rubyforge = RubyForge.new
|
71
|
+
rubyforge.login
|
72
|
+
|
73
|
+
if release_id = rubyforge.add_release(spec.rubyforge_project, spec.name, spec.version, "#{package}.tgz")
|
74
|
+
rubyforge.add_file(spec.rubyforge_project, spec.name, release_id, "#{package}.gem")
|
75
|
+
else
|
76
|
+
puts 'Release failed!'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/lib/powncer.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'cgi'
|
3
|
+
require 'net/http'
|
4
|
+
require 'base64'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
require 'powncer/ext'
|
8
|
+
require 'powncer/base'
|
9
|
+
require 'powncer/connection'
|
10
|
+
require 'powncer/authentication'
|
11
|
+
require 'powncer/user'
|
12
|
+
require 'powncer/note'
|
13
|
+
require 'powncer/link'
|
14
|
+
require 'powncer/event'
|
15
|
+
require 'powncer/media'
|
16
|
+
require 'powncer/version'
|
17
|
+
|
18
|
+
require_library_or_gem 'json'
|
19
|
+
|
20
|
+
begin; load "~/.powncer"; rescue LoadError; end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Powncer
|
2
|
+
|
3
|
+
module Authentication
|
4
|
+
|
5
|
+
class Basic < Connection
|
6
|
+
|
7
|
+
attr_accessor :options
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
super(true)
|
11
|
+
options[:username] ||= Basic.load_username
|
12
|
+
options[:password] ||= Basic.load_password
|
13
|
+
options[:application_key] ||= Basic.load_application_key
|
14
|
+
options[:secret_key] ||= Basic.load_secret_key
|
15
|
+
@options = options
|
16
|
+
Powncer.connections << self
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(uri)
|
20
|
+
super(uri, true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def post(uri, params={})
|
24
|
+
# TODO: Refactor
|
25
|
+
endpoint = "#{@url}#{uri}"
|
26
|
+
url = URI.parse(endpoint)
|
27
|
+
req = Net::HTTP::Post.new(url.path)
|
28
|
+
req.basic_auth(options[:username], options[:password])
|
29
|
+
# create hash to add Link, Event params to request
|
30
|
+
form_params = {}
|
31
|
+
form_params.merge!({'note_body' => params[:body]}) if params[:body]
|
32
|
+
form_params.merge!({'url' => params[:url]}) if params[:url]
|
33
|
+
form_params.merge!({'event_name' => params[:name]}) if params[:name]
|
34
|
+
form_params.merge!({'event_location' => params[:location]}) if params[:location]
|
35
|
+
form_params.merge!({'event_date' => params[:date]}) if params[:date]
|
36
|
+
form_params.merge!({'media_file' => params[:data]}) if params[:data]
|
37
|
+
req.set_content_type('multipart/form-data')
|
38
|
+
req.set_form_data({'app_key' => options[:application_key], 'note_to' => "#{params[:to]}"}.merge(form_params))
|
39
|
+
response = Net::HTTP.new(url.host, url.port).start { |http| http.request(req) }
|
40
|
+
response.body
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
|
45
|
+
[:username, :password, :application_key, :secret_key].each do |type|
|
46
|
+
class_eval(<<-EVAL, __FILE__, __LINE__)
|
47
|
+
def load_#{type}
|
48
|
+
env_key(:#{type})
|
49
|
+
end
|
50
|
+
EVAL
|
51
|
+
end
|
52
|
+
|
53
|
+
def connect!(options={})
|
54
|
+
self.new(options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def open(uri, options, *args, &block)
|
58
|
+
query_params = URI.parse(uri).query
|
59
|
+
headers = {}
|
60
|
+
headers["Authorization"] = Header.new(options[:username], options[:password])
|
61
|
+
uri << "#{query_params.nil? ? "?" : "&"}"
|
62
|
+
uri << "app_key=#{options[:application_key]}"
|
63
|
+
Kernel::open(uri, headers, *args, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def env_key(key_name)
|
67
|
+
ENV["POWNCER_#{key_name.to_s.upcase}"]
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class Header < String
|
73
|
+
|
74
|
+
def initialize(username, password)
|
75
|
+
self << "Basic #{Base64.encode64("#{username}:#{password}")}"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/powncer/base.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
module Powncer
|
2
|
+
|
3
|
+
class PowncerError < StandardError; end
|
4
|
+
class PownceConnectionError < PowncerError; end
|
5
|
+
class ConnectionUnavailable < PownceConnectionError; end
|
6
|
+
class BadResponse < PownceConnectionError; end
|
7
|
+
class WebServiceError < PownceConnectionError; end
|
8
|
+
class InvalidFriend < PowncerError; end
|
9
|
+
class RequirementMissing < PowncerError; end
|
10
|
+
class InvalidFormat < RequirementMissing; end
|
11
|
+
|
12
|
+
class Base
|
13
|
+
|
14
|
+
FORMAT = 'json'
|
15
|
+
|
16
|
+
def id
|
17
|
+
@attributes["id"] || nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def request(url)
|
21
|
+
self.class.request(url)
|
22
|
+
end
|
23
|
+
|
24
|
+
def post(url, *params)
|
25
|
+
self.class.post(url, params)
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def request(url)
|
31
|
+
response = Powncer.connect!.get(url)
|
32
|
+
parse(response)
|
33
|
+
end
|
34
|
+
|
35
|
+
def post(url, *params)
|
36
|
+
options = extract_options(params.flatten)
|
37
|
+
response = Powncer.connect!.post(url, options)
|
38
|
+
parse(response)
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse(response)
|
42
|
+
json = JSON.parse(response)
|
43
|
+
if json.has_key? 'error'
|
44
|
+
raise WebServiceError, json["error"]["message"]
|
45
|
+
end
|
46
|
+
return json
|
47
|
+
end
|
48
|
+
|
49
|
+
def instantiate(attributes)
|
50
|
+
object = allocate
|
51
|
+
object.instance_variable_set("@attributes", attributes)
|
52
|
+
object
|
53
|
+
end
|
54
|
+
|
55
|
+
def extract_options(args)
|
56
|
+
args.last.is_a?(Hash) ? args.pop : {}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def extract_attributes(args)
|
63
|
+
args.last.is_a?(Hash) ? args.pop : {}
|
64
|
+
end
|
65
|
+
|
66
|
+
alias :orig_method_missing :method_missing
|
67
|
+
|
68
|
+
def method_missing(method_id, *args)
|
69
|
+
attribute_name = method_id.to_s
|
70
|
+
if @attributes.stringify_keys!.has_key?(attribute_name)
|
71
|
+
return @attributes.fetch(method_id.to_s)
|
72
|
+
else
|
73
|
+
orig_method_missing(method_id, args)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
|
81
|
+
def connections
|
82
|
+
@connections ||= []
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_connection(connection)
|
86
|
+
connections << connection
|
87
|
+
end
|
88
|
+
|
89
|
+
def make_default_connection
|
90
|
+
add_connection(Connection.new).first
|
91
|
+
end
|
92
|
+
|
93
|
+
def connect!
|
94
|
+
connections.last || make_default_connection
|
95
|
+
end
|
96
|
+
|
97
|
+
def disconnect!
|
98
|
+
@connections.clear unless connections.empty?
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Powncer
|
2
|
+
|
3
|
+
class Connection
|
4
|
+
|
5
|
+
attr_accessor :url, :authenticated
|
6
|
+
|
7
|
+
def initialize(is_auth=false)
|
8
|
+
@url = "#{Powncer::Version::API_URL}/#{Powncer::Version::API_VERSION}"
|
9
|
+
@authenticated = is_auth
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(uri, use_auth=false)
|
13
|
+
endpoint = "#{@url}#{uri}"
|
14
|
+
begin
|
15
|
+
if use_auth
|
16
|
+
response = Authentication::Basic.open(endpoint, Powncer.connect!.options)
|
17
|
+
else
|
18
|
+
response = open(endpoint)
|
19
|
+
end
|
20
|
+
case response.status
|
21
|
+
when ["200", "OK"]
|
22
|
+
response.read
|
23
|
+
else
|
24
|
+
raise BadResponse
|
25
|
+
end
|
26
|
+
rescue
|
27
|
+
raise ConnectionUnavailable
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end #/Connection
|
32
|
+
|
33
|
+
end #/Powncer
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Powncer
|
2
|
+
|
3
|
+
class Event < Note
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
raise RequirementMissing, "Event requires a name" unless options[:name]
|
7
|
+
raise RequirementMissing, "Event requires a location" unless options[:location]
|
8
|
+
raise RequirementMissing, "Event requires a date" unless options[:date]
|
9
|
+
raise InvalidFormat, "Event date should be formatted YYYY-MM-DD hh:mm" unless options[:date].is_valid_date?
|
10
|
+
super
|
11
|
+
@attributes["name"] = options[:name]
|
12
|
+
@attributes["location"] = options[:location]
|
13
|
+
@attributes["date"] = options[:date]
|
14
|
+
end
|
15
|
+
|
16
|
+
[:name, :location, :date].each do |attribute|
|
17
|
+
class_eval(<<-EVAL, __FILE__, __LINE__)
|
18
|
+
def #{attribute}
|
19
|
+
@attributes["#{attribute}"] || @attributes["event"]["#{attribute}"]
|
20
|
+
end
|
21
|
+
EVAL
|
22
|
+
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
|
26
|
+
def create(attributes)
|
27
|
+
attributes.symbolize_keys!
|
28
|
+
event = self.new(attributes)
|
29
|
+
unless event.to.is_a?(Symbol)
|
30
|
+
target_key = self.superclass.ensure_send_to(:friend, event.to)
|
31
|
+
end
|
32
|
+
url = "/send/event.#{self.superclass::FORMAT}"
|
33
|
+
Event.instantiate post(url, {:to => target_key || event.to, :name => event.name, :location => event.location, :date => event.date})
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/powncer/ext.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
class Hash
|
3
|
+
def to_query
|
4
|
+
query_string = self.empty? ? "" : "?"
|
5
|
+
query_array = []
|
6
|
+
self.map.each{|ary| query_array << "#{ary.first}=#{ary.last}"}
|
7
|
+
query_string << query_array.join("&")
|
8
|
+
end
|
9
|
+
def stringify_keys
|
10
|
+
inject({}) do |options, (key, value)|
|
11
|
+
options[key.to_s] = value
|
12
|
+
options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def stringify_keys!
|
16
|
+
self.replace(self.stringify_keys)
|
17
|
+
end
|
18
|
+
def symbolize_keys
|
19
|
+
inject({}) do |options, (key, value)|
|
20
|
+
options[key.to_sym || key] = value
|
21
|
+
options
|
22
|
+
end
|
23
|
+
end
|
24
|
+
def symbolize_keys!
|
25
|
+
self.replace(self.symbolize_keys)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class String
|
30
|
+
def is_valid_url?
|
31
|
+
return true if self =~ /http\:\/\//
|
32
|
+
end
|
33
|
+
def is_valid_date?
|
34
|
+
return !/\d{4}\-\d{2}\-\d{2}\s\d{2}\:\d{2}/.match(self).nil?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Kernel
|
39
|
+
def require_library_or_gem(library)
|
40
|
+
require library
|
41
|
+
rescue LoadError => library_not_installed
|
42
|
+
begin
|
43
|
+
require 'rubygems'
|
44
|
+
require library
|
45
|
+
rescue LoadError
|
46
|
+
raise library_not_installed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module Net
|
52
|
+
module HTTPHeader
|
53
|
+
def set_form_data(params, sep = '&')
|
54
|
+
self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep)
|
55
|
+
self.content_type ||= 'application/x-www-form-urlencoded'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/powncer/link.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Powncer
|
2
|
+
|
3
|
+
class Link < Note
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
options[:url] ||= ""
|
7
|
+
raise RequirementMissing unless options[:url].is_valid_url?
|
8
|
+
super
|
9
|
+
@attributes["url"] = options[:url]
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def create(attributes)
|
15
|
+
attributes.symbolize_keys!
|
16
|
+
link = self.new(attributes)
|
17
|
+
unless link.to.is_a?(Symbol)
|
18
|
+
target_key = self.superclass.ensure_send_to(:friend, link.to)
|
19
|
+
end
|
20
|
+
url = "/send/link.#{self.superclass::FORMAT}"
|
21
|
+
Link.instantiate post(url, {:body => link.body, :to => target_key || link.to, :url => link.url})
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|