powncer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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