ubiquitously 0.0.1.6 → 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.
Files changed (114) hide show
  1. data/README.markdown +224 -19
  2. data/Rakefile +12 -4
  3. data/bin/u.me +4 -0
  4. data/lib/ubiquitously.rb +56 -7
  5. data/lib/ubiquitously/commands/base.rb +118 -0
  6. data/lib/ubiquitously/commands/post.rb +108 -0
  7. data/lib/ubiquitously/commands/user.rb +111 -0
  8. data/lib/ubiquitously/extensions/callbacks.rb +62 -0
  9. data/lib/ubiquitously/extensions/core.rb +88 -0
  10. data/lib/ubiquitously/extensions/mechanize.rb +35 -0
  11. data/lib/ubiquitously/models/base.rb +18 -0
  12. data/lib/ubiquitously/models/page.rb +28 -0
  13. data/lib/ubiquitously/models/post.rb +66 -0
  14. data/lib/ubiquitously/models/service.rb +1 -0
  15. data/lib/ubiquitously/models/service/account.rb +57 -0
  16. data/lib/ubiquitously/models/service/account/authorizable.rb +58 -0
  17. data/lib/ubiquitously/models/service/account/loggable.rb +50 -0
  18. data/lib/ubiquitously/models/service/account/restful.rb +21 -0
  19. data/lib/ubiquitously/models/service/post.rb +59 -0
  20. data/lib/ubiquitously/models/service/post/loggable.rb +64 -0
  21. data/lib/ubiquitously/models/service/post/ownable.rb +31 -0
  22. data/lib/ubiquitously/models/service/post/postable.rb +73 -0
  23. data/lib/ubiquitously/models/service/post/restful.rb +52 -0
  24. data/lib/ubiquitously/models/user.rb +128 -0
  25. data/lib/ubiquitously/services/blogger_den.rb +68 -0
  26. data/lib/ubiquitously/services/chetzit.rb +37 -0
  27. data/lib/ubiquitously/services/code_project.rb +21 -0
  28. data/lib/ubiquitously/services/delicious.rb +54 -0
  29. data/lib/ubiquitously/services/design_bump.rb +41 -0
  30. data/lib/ubiquitously/services/designgizer.rb +21 -0
  31. data/lib/ubiquitously/services/designr_fix.rb +21 -0
  32. data/lib/ubiquitously/services/digg.rb +151 -0
  33. data/lib/ubiquitously/services/digzign.rb +25 -0
  34. data/lib/ubiquitously/services/diigo.rb +68 -0
  35. data/lib/ubiquitously/services/dzone.rb +132 -0
  36. data/lib/ubiquitously/services/dzone_snippets.rb +39 -0
  37. data/lib/ubiquitously/services/facebook.rb +42 -0
  38. data/lib/ubiquitously/services/faves.rb +81 -0
  39. data/lib/ubiquitously/services/favshare.rb +78 -0
  40. data/lib/ubiquitously/services/flikode.rb +38 -0
  41. data/lib/ubiquitously/services/friendfeed.rb +21 -0
  42. data/lib/ubiquitously/services/gist.rb +52 -0
  43. data/lib/ubiquitously/services/google_buzz.rb +15 -0
  44. data/lib/ubiquitously/services/identica.rb +15 -0
  45. data/lib/ubiquitously/services/jump_tags.rb +21 -0
  46. data/lib/ubiquitously/services/kailoon.rb +27 -0
  47. data/lib/ubiquitously/services/meta_filter.rb +26 -0
  48. data/lib/ubiquitously/services/mixx.rb +94 -0
  49. data/lib/ubiquitously/services/mmo.rb +22 -0
  50. data/lib/ubiquitously/services/mvc_forge.rb +37 -0
  51. data/lib/ubiquitously/services/my_space.rb +25 -0
  52. data/lib/ubiquitously/services/nestdev.rb +36 -0
  53. data/lib/ubiquitously/services/newsvine.rb +76 -0
  54. data/lib/ubiquitously/services/pixel_groovy.rb +22 -0
  55. data/lib/ubiquitously/services/posterous.rb +24 -0
  56. data/lib/ubiquitously/services/programmers_heaven.rb +21 -0
  57. data/lib/ubiquitously/{propeller.rb → services/propeller.rb} +17 -26
  58. data/lib/ubiquitously/services/queness.rb +38 -0
  59. data/lib/ubiquitously/services/reddit.rb +62 -0
  60. data/lib/ubiquitously/services/scribd.rb +21 -0
  61. data/lib/ubiquitously/services/script_and_style.rb +23 -0
  62. data/lib/ubiquitously/services/sharebrain.rb +19 -0
  63. data/lib/ubiquitously/services/shoutwire.rb +34 -0
  64. data/lib/ubiquitously/services/slideshare.rb +70 -0
  65. data/lib/ubiquitously/services/smipple.rb +21 -0
  66. data/lib/ubiquitously/services/snipplr.rb +67 -0
  67. data/lib/ubiquitously/services/snipt.rb +49 -0
  68. data/lib/ubiquitously/services/sphinn.rb +24 -0
  69. data/lib/ubiquitously/services/stumble_upon.rb +67 -0
  70. data/lib/ubiquitously/services/stumpedia.rb +13 -0
  71. data/lib/ubiquitously/services/tumblr.rb +28 -0
  72. data/lib/ubiquitously/services/tweako.rb +53 -0
  73. data/lib/ubiquitously/services/twitter.rb +60 -0
  74. data/lib/ubiquitously/services/web_blend.rb +25 -0
  75. data/lib/ubiquitously/services/webdev5.rb +32 -0
  76. data/lib/ubiquitously/services/who_freelance.rb +21 -0
  77. data/lib/ubiquitously/services/wordtaps.rb +36 -0
  78. data/lib/ubiquitously/services/yahoo_buzz.rb +64 -0
  79. data/lib/ubiquitously/services/youblr.rb +15 -0
  80. data/lib/ubiquitously/services/zabox.rb +22 -0
  81. data/lib/ubiquitously/support/active_record.rb +25 -0
  82. data/lib/ubiquitously/support/storage.rb +71 -0
  83. data/test/config/cookies.yml +111 -0
  84. data/test/config/credentials.yml +7 -0
  85. data/test/config/secrets.yml +33 -0
  86. data/test/config/tokens.yml +30 -0
  87. data/test/meta.html +19 -0
  88. data/test/test_delicious.rb +37 -0
  89. data/test/test_digg.rb +57 -0
  90. data/test/test_dzone.rb +23 -18
  91. data/test/test_facebook.rb +40 -0
  92. data/test/test_faves.rb +18 -20
  93. data/test/test_helper.rb +8 -1
  94. data/test/test_newsvine.rb +3 -3
  95. data/test/test_page.rb +21 -0
  96. data/test/test_post.rb +55 -0
  97. data/test/test_propeller.rb +2 -2
  98. data/test/test_reddit.rb +26 -4
  99. data/test/test_stumble_upon.rb +23 -3
  100. data/test/test_twitter.rb +33 -0
  101. data/test/test_user.rb +22 -0
  102. metadata +199 -24
  103. data/lib/ext.rb +0 -37
  104. data/lib/ubiquitously/base.rb +0 -56
  105. data/lib/ubiquitously/dzone.rb +0 -111
  106. data/lib/ubiquitously/faves.rb +0 -43
  107. data/lib/ubiquitously/mister_wong.rb +0 -11
  108. data/lib/ubiquitously/mixins/resourceful.rb +0 -50
  109. data/lib/ubiquitously/mixx.rb +0 -66
  110. data/lib/ubiquitously/newsvine.rb +0 -54
  111. data/lib/ubiquitously/reddit.rb +0 -46
  112. data/lib/ubiquitously/sphinn.rb +0 -11
  113. data/lib/ubiquitously/stumble_upon.rb +0 -61
  114. data/test/config.yml +0 -18
@@ -0,0 +1,66 @@
1
+ module Ubiquitously
2
+ class Post < Base
3
+ attr_accessor :url, :title, :description, :tags, :categories, :user, :page, :posts, :format, :extension
4
+
5
+ def initialize(attributes = {})
6
+ apply attributes
7
+ raise 'please pass Post a User' if self.user.blank?
8
+ self.posts ||= []
9
+ end
10
+
11
+ def page
12
+ @page ||= Ubiquitously::Page.new(:url => self.url).parse
13
+ end
14
+
15
+ # create or update
16
+ def save(*services)
17
+ options = services.extract_options!
18
+ postables(*services).map { |post| post.save }
19
+ end
20
+
21
+ def new_record?(service, &block)
22
+ postables(*service).detect do |post|
23
+ post.new_record?
24
+ end
25
+ end
26
+
27
+ def postables(*services)
28
+ services = services.flatten.map(&:to_sym)
29
+ result = services.map do |service|
30
+ if service.is_a?(Ubiquitously::Service::Post)
31
+ service
32
+ else
33
+ "Ubiquitously::#{service.to_s.camelize}::Post".constantize.new(
34
+ :user => self.user,
35
+ :url => self.url,
36
+ :title => self.title,
37
+ :description => self.description,
38
+ :tags => self.tags,
39
+ :categories => self.categories,
40
+ :format => self.format,
41
+ :extension => self.extension
42
+ )
43
+ end
44
+ end.uniq
45
+
46
+ self.posts = self.posts.concat(result)
47
+
48
+ self.posts.select { |post| services.include?(post.service.to_sym) }
49
+ end
50
+
51
+ Ubiquitously.services.each do |service|
52
+ define_method service do
53
+ postables(service).first
54
+ end
55
+
56
+ define_method "#{service.to_s}?" do
57
+ !send(service).new_record?
58
+ end
59
+ end
60
+
61
+ def inspect
62
+ "#<#{self.class.inspect} @url=#{self.url.inspect} @title=#{self.title.inspect} @description=#{self.description.inspect} @tags=#{self.tags.inspect}>"
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1 @@
1
+ Dir["#{File.dirname(__FILE__)}/service/*"].each { |c| require c unless File.directory?(c) }
@@ -0,0 +1,57 @@
1
+ Dir["#{File.dirname(__FILE__)}/account/*"].each { |c| require c unless File.directory?(c) }
2
+
3
+ module Ubiquitously
4
+ module Service
5
+ class Account < Ubiquitously::Base
6
+ include Ubiquitously::Account::Restful
7
+ include Ubiquitously::Account::Loggable
8
+ include Ubiquitously::Account::Authorizable
9
+
10
+ attr_accessor :username, :password, :credentials
11
+ attr_accessor :logged_in, :ip, :user
12
+
13
+ def initialize(attributes = {})
14
+ attributes = attributes.symbolize_keys
15
+
16
+ attributes[:username] = Ubiquitously.key("#{service}.key") if attributes[:username].blank?
17
+ attributes[:password] = Ubiquitously.key("#{service}.secret") if attributes[:password].blank?
18
+
19
+ if attributes[:username].blank? || attributes[:password].blank?
20
+ raise "Where is the username and password for #{service}?"
21
+ end
22
+
23
+ @logged_in = false
24
+
25
+ apply attributes
26
+ end
27
+
28
+ def credentials
29
+ @credentials ||= {}
30
+ end
31
+
32
+ def agent
33
+ user.agent
34
+ end
35
+
36
+ def cookies?
37
+ user.cookies_for?(service)
38
+ end
39
+
40
+ def credentials?
41
+ !self.credentials.blank?
42
+ end
43
+
44
+ def access_token
45
+ if uses?(:oauth) && @access_token.blank?
46
+ @access_token = "#{service.camelize}Token".constantize.new
47
+ @access_token.token = credentials["token"]
48
+ @access_token.secret = credentials["secret"]
49
+ @access_token.key = credentials["key"]
50
+ end
51
+
52
+ @access_token
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ module Ubiquitously
2
+ module Account
3
+ module Authorizable
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.validates_presence_of :username, :password
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def uses(*protocols)
12
+ @uses = protocols.flatten.map(&:to_s) unless protocols.blank?
13
+ @uses ||= []
14
+ @uses
15
+ end
16
+
17
+ def uses?(protocol)
18
+ uses.include?(protocol.to_s)
19
+ end
20
+ end
21
+
22
+ module InstanceMethods
23
+ def authorize!(condition)
24
+ authorize(condition)
25
+
26
+ unless logged_in?
27
+ raise AuthenticationError.new("Invalid username or password for #{service.titleize}")
28
+ end
29
+
30
+ logged_in?
31
+ end
32
+
33
+ def authorize(condition)
34
+ @logged_in = !!condition
35
+ end
36
+
37
+ def logged_in?
38
+ @logged_in == true
39
+ end
40
+
41
+ def uses?(protocol)
42
+ self.class.uses?(protocol)
43
+ end
44
+
45
+ def requires_credentials?
46
+ uses?(:oauth)
47
+ end
48
+
49
+ def authorized?
50
+ return true if logged_in?
51
+ return (credentials? && cookies?) if requires_credentials?
52
+ return cookies?
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,50 @@
1
+ module Ubiquitously
2
+ module Account
3
+ module Loggable
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.loggable
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def loggable
12
+ before_login do
13
+ if authorized?
14
+ @logged_in = true
15
+ return false
16
+ end
17
+ logger.info "[login:before] #{inspect}"
18
+ end
19
+
20
+ after_login do
21
+ user.save
22
+ logger.info "[login:after] #{inspect}"
23
+ end
24
+ end
25
+
26
+ def service
27
+ name.split("::")[1].underscore.gsub(/\s+/, "_")
28
+ end
29
+
30
+ def logger
31
+ Ubiquitously.logger
32
+ end
33
+ end
34
+
35
+ module InstanceMethods
36
+ def logger
37
+ self.class.logger
38
+ end
39
+
40
+ def service
41
+ self.class.service
42
+ end
43
+
44
+ def inspect
45
+ "#<#{self.class.inspect} @username=#{username.inspect} @password=#{password.gsub(/./, "*").inspect} @service=#{service.inspect}>"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module Account
3
+ module Restful
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.restful
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def restful
12
+ subclassable_callbacks :login
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ Dir["#{File.dirname(__FILE__)}/post/*"].each { |c| require c unless File.directory?(c) }
2
+
3
+ module Ubiquitously
4
+ module Service
5
+ class Post < Ubiquitously::Base
6
+ include Ubiquitously::Ownable::Post
7
+ include Ubiquitously::Postable::Post
8
+ include Ubiquitously::Restful::Post
9
+ include Ubiquitously::Loggable::Post
10
+
11
+ #validates_presence_of :title, :description, :tags
12
+ attr_accessor :token
13
+ attr_accessor :title, :url, :description, :tags, :categories, :remote, :service_id
14
+ # some sites check to see if you're posting duplicate content!
15
+ # perhaps "vote" can mean "favorite" also
16
+ attr_accessor :image, :rating, :privacy, :vote, :status, :must_be_unique, :captcha
17
+ attr_accessor :service_url, :user, :upvotes, :downvotes
18
+ # the application that automates! ("Posted by TweetMeme")
19
+ attr_accessor :source, :source_url
20
+ # kind == regular, link, quote, photo, conversation, video, audio, answer
21
+ attr_accessor :kind
22
+ # plain, html, markdown
23
+ attr_accessor :format, :extension
24
+ # max 55 chars, for custom url if possible
25
+ attr_accessor :slug
26
+ # published, draft, submission, queue
27
+ attr_accessor :state
28
+
29
+ before_create { self.token = tokenize }
30
+ before_update { self.token = tokenize }
31
+ after_create { self.token = nil }
32
+ after_update { self.token = nil }
33
+
34
+ def initialize(attributes = {})
35
+ apply attributes
36
+
37
+ raise 'please give me a user' if self.user.blank?
38
+
39
+ self.format ||= "text"
40
+ self.privacy = 0 if self.privacy.nil?
41
+ self.categories ||= []
42
+ self.tags ||= []
43
+ self.upvotes ||= 0
44
+ self.downvotes ||= 0
45
+
46
+ # for httparty
47
+ @auth = {:username => username, :password => password}
48
+ end
49
+
50
+ def remote
51
+ @remote ||= self.class.find(:url => self.url, :user => self.user)
52
+ end
53
+
54
+ def access_token
55
+ user.account_for(self).access_token
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,64 @@
1
+ module Ubiquitously
2
+ module Loggable
3
+ module Post
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.loggable
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def logger
12
+ Ubiquitously.logger
13
+ end
14
+
15
+ def loggable
16
+ before_create do
17
+ unless valid?
18
+ logger.info "[invalid] #{errors.full_messages}"
19
+ return false
20
+ end
21
+ authorize
22
+ return false unless new_record?
23
+ logger.info "[create:before] #{tokenize.inspect}"
24
+ end
25
+
26
+ after_create do
27
+ logger.info "[create:after] #{tokenize.inspect}"
28
+ end
29
+
30
+ before_update do
31
+ unless valid?
32
+ logger.info "[invalid] #{errors.full_messages}"
33
+ return false
34
+ end
35
+ authorize
36
+ logger.info "[update:before] #{tokenize.inspect}"
37
+ end
38
+
39
+ after_update do
40
+ logger.info "[update:after] #{tokenize.inspect}"
41
+ end
42
+ end
43
+
44
+ def service
45
+ to_s.split("::")[1].underscore.gsub(/\s+/, "_").downcase
46
+ end
47
+ end
48
+
49
+ module InstanceMethods
50
+ def service
51
+ self.class.service
52
+ end
53
+
54
+ def logger
55
+ self.class.logger
56
+ end
57
+
58
+ def inspect
59
+ "#<#{self.class.inspect} @url=#{self.url.inspect} @title=#{self.title.inspect} @tags=#{self.tags.inspect} @categories=#{self.categories.inspect}>"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,31 @@
1
+ module Ubiquitously
2
+ module Ownable
3
+ module Post
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ end
11
+
12
+ module InstanceMethods
13
+ def agent
14
+ user.agent
15
+ end
16
+
17
+ def username
18
+ user.username_for(self)
19
+ end
20
+
21
+ def password
22
+ user.password_for(self)
23
+ end
24
+
25
+ def authorize
26
+ user.login(service)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,73 @@
1
+ module Ubiquitously
2
+ module Postable
3
+ module Post
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def submit_to(url = nil)
12
+ @submit_to = url if url
13
+ @submit_to
14
+ end
15
+
16
+ def submit_url(post)
17
+ post.tokenize.inject(submit_to) do |result, token|
18
+ result.gsub(/:#{token.first}/, token.last)
19
+ end
20
+ end
21
+
22
+ # with and without trailing slash, in case we saved it as one over the other
23
+ def url_permutations(url)
24
+ url, params = url.split("?")
25
+ # without_trailing_slash, with www
26
+ a = url.gsub(/\/$/, "").gsub(/http(s)?:\/\/([^\/]+)/) do |match|
27
+ protocol = "http#{$1.to_s}"
28
+ domain = $2
29
+ domain = "www.#{domain}" if domain.split(".").length < 3 # www.google.com == 3, google.com == 2
30
+ "#{protocol}://#{domain}"
31
+ end
32
+ # with_trailing_slash, with www
33
+ b = "#{a}/"
34
+ # without_trailing_slash, without www
35
+ c = a.gsub(/http(s)?:\/\/www\./, "http#{$1.to_s}://")
36
+ # with_trailing_slash, without www
37
+ d = "#{c}/"
38
+
39
+ [a, b, c, d].map { |url| "#{url}?#{params}".gsub(/\?$/, "") }
40
+ end
41
+
42
+ end
43
+
44
+ module InstanceMethods
45
+ def tokenize
46
+ {
47
+ :url => self.url,
48
+ :title => self.title,
49
+ :description => self.description,
50
+ :tags => self.tags.map { |tag| tag.downcase.gsub(/[^a-z0-9\.]/, " ").squeeze(" ") }.join(", "),
51
+ :categories => self.categories.map { |tag| tag.downcase.gsub(/[^a-z0-9\.]/, " ").squeeze(" ") }
52
+ }
53
+ end
54
+
55
+ def private?
56
+ privacy == 1 || privacy == "1" || privacy == "private"
57
+ end
58
+
59
+ def public?
60
+ privacy == 0 || privacy == "0" || privacy == "public"
61
+ end
62
+
63
+ def url_permutations(url)
64
+ self.class.url_permutations(url)
65
+ end
66
+
67
+ def submit_url
68
+ self.class.submit_url(self)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end