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,52 @@
1
+ module Ubiquitously
2
+ module Restful
3
+ module Post
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 :create, :update, :destroy
13
+ end
14
+
15
+ def create(attributes = {})
16
+ record = new(attributes)
17
+ record.save
18
+ record
19
+ end
20
+
21
+ def create!(attributes = {})
22
+ record = new(attributes)
23
+ record.save!
24
+ record
25
+ end
26
+
27
+ def find(options = {})
28
+ nil
29
+ end
30
+ end
31
+
32
+ module InstanceMethods
33
+
34
+ def save
35
+ create_or_update
36
+ end
37
+
38
+ def create_or_update
39
+ new_record? ? create : update
40
+ end
41
+
42
+ def save!
43
+ save || raise(Ubiquitously::RecordInvalid.new("Record is invalid: #{self.errors.full_messages}"))
44
+ end
45
+
46
+ def new_record?
47
+ self.remote.blank?
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,128 @@
1
+ module Ubiquitously
2
+ class User < Base
3
+ attr_accessor :username, :name, :email
4
+ attr_accessor :agent, :cookies, :accounts, :storage
5
+
6
+ def initialize(attributes = {})
7
+ attributes = attributes.symbolize_keys
8
+
9
+ raise "Please define 'storage'" unless attributes[:storage]
10
+
11
+ unless attributes[:agent]
12
+ attributes[:agent] = Mechanize.new
13
+ #attributes[:agent].log = Logger.new(STDOUT)
14
+ attributes[:agent].user_agent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; ru-ru) AppleWebKit/533.2+ (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"
15
+ end
16
+
17
+ if attributes[:storage].is_a?(String)
18
+ attributes[:storage] = Ubiquitously::Storage::FileSystem.new(attributes[:storage])
19
+ end
20
+
21
+ apply attributes
22
+ end
23
+
24
+ def accounts
25
+ @accounts ||= []
26
+ end
27
+
28
+ def accountables(*items, &block)
29
+ services = items.flatten.map(&:to_s)
30
+ services.each do |service|
31
+ next if self.accounts.detect { |account| account.service == service }
32
+ clazz = "Ubiquitously::#{service.camelize}::Account".constantize
33
+ if block_given?
34
+ self.accounts << yield(clazz)
35
+ else
36
+ self.accounts << clazz.new(:user => self)
37
+ end
38
+ end
39
+ self.accounts.select { |account| services.include?(account.service) }
40
+ end
41
+
42
+ def account_classes(*items)
43
+ services = items.flatten.map(&:to_s)
44
+ services.map do |service|
45
+ "Ubiquitously::#{service.camelize}::Account".constantize
46
+ end.select { |account| services.include?(account.service) }
47
+ end
48
+
49
+ def login(*services)
50
+ load
51
+ accountables(*services).map(&:login)
52
+ save
53
+ true
54
+ end
55
+
56
+ def load
57
+ apply storage.load
58
+ end
59
+
60
+ def save
61
+ storage.save(cookies, credentials)
62
+ end
63
+
64
+ def cookies
65
+ self.agent.cookie_jar.jar
66
+ end
67
+
68
+ def cookies=(hash)
69
+ agent.cookie_jar.jar = hash
70
+ end
71
+
72
+ def credentials
73
+ self.accounts.inject({}) do |hash, account|
74
+ hash[account.service] = account.credentials.stringify_keys
75
+ hash
76
+ end
77
+ end
78
+
79
+ def credentials=(hash)
80
+ accountables(hash.keys).each do |account|
81
+ account.credentials.merge!(hash[account.service])
82
+ end
83
+ end
84
+
85
+ def cookies_for(service)
86
+ name = service_cookie_name(service.to_s)
87
+ result = cookies.keys.detect { |domain| domain.downcase =~ /#{name}/ }
88
+ return nil if result.blank?
89
+ uri = URI.parse("http://#{result}")
90
+ unless agent.cookie_jar.empty?(uri)
91
+ cookies = agent.cookie_jar.cookies(uri)
92
+ cookie = cookies.length > 0 ? cookies.join("; ") : nil
93
+ else
94
+ cookie = nil
95
+ end
96
+ end
97
+
98
+ def cookies_for?(service)
99
+ !cookies_for(service).blank?
100
+ end
101
+
102
+ def credentials_for(service)
103
+ credentials[service.to_s]
104
+ end
105
+
106
+ def credentials_for?(service)
107
+ !credentials_for(service).blank?
108
+ end
109
+
110
+ def service_cookie_name(service)
111
+ return service.gsub("_", "_?") unless service == "dzone_snippets"
112
+ return "dzone"
113
+ end
114
+
115
+ def username_for(service)
116
+ account_for(service).username
117
+ end
118
+
119
+ def password_for(service)
120
+ account_for(service).password
121
+ end
122
+
123
+ def account_for(service)
124
+ service = service.service unless service.is_a?(String)
125
+ accountables(*service).detect { |account| account.service == service }
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,68 @@
1
+ module Ubiquitously
2
+ module BloggerDen
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://www.bloggerden.com/login")
6
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Like Digg/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ # title max length == 120
17
+ submit_to "http://digg.com/submit?phase=2&url=:url&title=:title&bodytext=:description&topic=26"
18
+
19
+ def tokenize
20
+ super.merge(:title => self.title[0..120])
21
+ end
22
+
23
+ def create
24
+ # url
25
+ page = agent.get("http://www.bloggerden.com/submit/")
26
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
27
+
28
+ form["url"] = url
29
+
30
+ page = form.submit
31
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
32
+
33
+ form["title"] = title
34
+ form["bodytext"] = description # 350 chars max
35
+ form.radiobuttons_with(:name => "category").each do |button|
36
+ button.check if button.value.to_s == "38"
37
+ end
38
+
39
+ iframe_url = page.parser.css("noscript iframe").first["src"]
40
+ params = iframe_url.split("?").last
41
+ captcha_iframe = agent.click(page.iframes.first)
42
+ captcha_form = captcha_iframe.forms.first
43
+ captcha_image = captcha_iframe.parser.css("img").first["src"]
44
+ # open browser with captcha image
45
+ system("open", "http://api.recaptcha.net/#{captcha_image}")
46
+ # enter captcha response in terminal
47
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
48
+ captcha_form["recaptcha_response_field"] = captcha_says
49
+ # submit captcha
50
+ captcha_form.action = "http://www.google.com/recaptcha/api/noscript?#{params}"
51
+ captcha_response = captcha_form.submit
52
+ # grab secret
53
+ captcha_response = captcha_response.parser.css("textarea").first.text
54
+
55
+ form["recaptcha_challenge_field"] = captcha_response
56
+ form["recaptcha_response_field"] = "manual_challenge"
57
+
58
+ page = form.submit
59
+ unless debug?
60
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
61
+ page = form.submit
62
+ end
63
+ # has captcha, not done with this
64
+ true
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ module Ubiquitously
2
+ module Chetzit
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://chetzit.com/login/")
6
+ form = page.forms.first
7
+ form["login"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title !~ /^Login/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://chetzit.com/link/add/")
18
+ form = page.forms.detect do |form|
19
+ !form.form_node.css("input[name=security_ls_key]").first.blank?
20
+ end
21
+
22
+ form.field_with(:name => "blog_id").options.first.select
23
+
24
+ form["topic_title"] = token[:title]
25
+ form["topic_link_url"] = token[:url]
26
+ # max 500 chars
27
+ form["topic_text"] = token[:description]
28
+ form["topic_tags"] = token[:tags]
29
+ form["submit_topic_publish"] = "Submit New"
30
+
31
+ page = form.submit(form.buttons.first)
32
+
33
+ true
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module CodeProject
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://www.codeproject.com/script/Articles/Submit.aspx")
6
+ form = page.form_with(:name => "subForm")
7
+ form["Email"] = email
8
+ form["Password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Article Submission/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://www.codeproject.com/script/Articles/SubmitStep1.aspx")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ module Ubiquitously
2
+ module Delicious
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ true
6
+ end
7
+ end
8
+
9
+ class Post < Ubiquitously::Service::Post
10
+ include HTTParty
11
+ base_uri 'https://api.del.icio.us/v1'
12
+ submit_to "http://del.icio.us/post/?url=:url&title=:title&notes=:description&tags=:tags"
13
+
14
+ def tokenize
15
+ super.merge(:tags => tags.taggify("-", " "))
16
+ end
17
+
18
+ def create
19
+ puts "CREATE #{@auth.inspect}"
20
+ res = self.class.get(
21
+ "/posts/add",
22
+ :query => {
23
+ :url => url,
24
+ :description => title,
25
+ :extended => description,
26
+ :tags => tags.map { |tag| tag.downcase.gsub(/[^a-z0-9]/, "-").squeeze("-") }.join(" ")
27
+ },
28
+ :basic_auth => @auth
29
+ )
30
+ puts "RESPONSE: #{res.inspect}"
31
+ true
32
+ end
33
+
34
+ def remote(options = {})
35
+ return nil
36
+ raise "what url to do want" if self.url.nil?
37
+ @remote ||= self.class.find(options.merge(
38
+ :query => {
39
+ :url => CGI.escape(self.url)
40
+ },
41
+ :basic_auth => @auth
42
+ ))
43
+ end
44
+
45
+ class << self
46
+ def find(options = {})
47
+ options[:result] = options.delete(:count) unless options[:count].nil?
48
+ raise "enter ':basic_auth => {:username => x, :password => y}'" unless options[:basic_auth]
49
+ self.get('/posts/get', options)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Ubiquitously
2
+ module DesignBump
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://designbump.com/login")
6
+ form = page.forms.detect { |form| form.form_node["id"] == "user-login-form" }
7
+ form["name"] = username
8
+ form["pass"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "http://designbump.com/user?destination=login")
12
+ end
13
+ end
14
+
15
+ # drupal
16
+ class Post < Ubiquitously::Service::Post
17
+
18
+ def tokenize
19
+ super.merge(:tags => tags.taggify(" ", :quote => true))
20
+ end
21
+
22
+ def create
23
+ page = agent.get("http://designbump.com/submit")
24
+ form = page.form_with(:action => "/submit")
25
+
26
+ form["url"] = token[:url]
27
+ form["title"] = token[:title]
28
+ form["body"] = token[:description]
29
+ form.field_with(:name => "taxonomy[1]").options.each do |option|
30
+ option.select if option.value.to_s == "21"
31
+ end
32
+ form["taxonomy[tags][2]"] = token[:tags]
33
+ form["op"] = "Save"
34
+
35
+ page = form.submit
36
+
37
+ true
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module Designgizer
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://service.com/login")
6
+ form = page.form_with(:name => "loginform")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Some title/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module DesignrFix
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://service.com/login")
6
+ form = page.form_with(:name => "loginform")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Some title/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("")
18
+ end
19
+ end
20
+ end
21
+ end