powncer 0.1.0

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