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,81 @@
1
+ module Ubiquitously
2
+ module Faves
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://secure.faves.com/signIn")
6
+ form = page.forms.detect {|form| form.form_node["id"] == "signInBox"}
7
+ form["rUsername"] = username
8
+ form["rPassword"] = password
9
+ form["action"] = "Sign In"
10
+ page = form.submit
11
+
12
+ authorize!(page.title !~ /Sign In/i)
13
+ end
14
+ end
15
+
16
+ class Post < Ubiquitously::Service::Post
17
+ def create
18
+ page = agent.get("http://faves.com/createdot.aspx")
19
+ form = page.form_with(:name => "createDotForm")
20
+ form["noteText"] = description
21
+ form["urlText"] = url
22
+ form["subjectText"] = title
23
+ form["tagsText"] = tags.join(", ")
24
+ form.field_with(:name => "rateSelect").options.each do |option|
25
+ option.select if option.value.to_s == "5"
26
+ end
27
+ form.field_with(:name => "shareSelect").options.each do |option|
28
+ option.select if option.value.to_s.downcase == "public"
29
+ end
30
+ # hidden fields they fill out with javascript
31
+ # form["imageUrl"] = "http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png"
32
+ # form["imageWidth"] = "149"
33
+ # form["imageHeight"] = "149"
34
+ # just before you submit the form they append the current time, so they have a range.
35
+ # mimic the range of time :)
36
+ form["authoringExpiry"] = form["authoringExpiry"] + "loadedtime=#{1.minute.ago.to_i * 1000}publishedtime=#{Time.now.to_i * 1000}"
37
+ headers = {
38
+ "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
39
+ "Keep-Alive" => "115",
40
+ "Accept-Encoding" => "gzip,deflate"
41
+ }
42
+
43
+ unless debug?
44
+ page = form.submit(nil, headers)
45
+ end
46
+
47
+ self
48
+ end
49
+
50
+ class << self
51
+ def find(options = {})
52
+ result = []
53
+ user = options[:user]
54
+ user_url = "http://faves.com/users/#{user.username_for(self)}"
55
+ html = Nokogiri::HTML(open(user_url).read)
56
+
57
+ html.css(".userDotList li").each do |node|
58
+ next if node["id"].blank?
59
+ url = node.css(".note > a").first["href"]
60
+ title = node.css(".note > p").first.text
61
+ tags = []
62
+ node.xpath("a").each do |tag|
63
+ tags << tag.text if tag["class"].blank?
64
+ end
65
+ record = new(
66
+ :title => title,
67
+ :url => url,
68
+ :tags => tags
69
+ )
70
+ if options[:url] && options[:url] == record.url
71
+ return record
72
+ end
73
+ result << record
74
+ end
75
+
76
+ options[:url] ? nil : result
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,78 @@
1
+ module Ubiquitously
2
+ module Favshare
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://favshare.net/login.php")
6
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
7
+ form["username"] = username
8
+ form["password"] = password
9
+ form["persistent"] = "persistent"
10
+ form["processlogin"] = "1"
11
+ page = form.submit
12
+
13
+ end
14
+ end
15
+
16
+ # see your posts here: http://favshare.net/user/history/viatropos/
17
+ class Post < Ubiquitously::Service::Post
18
+
19
+ # max tags == 40 chars
20
+ def tokenize
21
+ super.merge(:tags => tags.taggify(" ", ", ", 40))
22
+ end
23
+
24
+ def create
25
+ page = agent.get("http://favshare.net/submit.php")
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["summarytext"] = description
36
+ # MALFORMATTED HTML: select box is outside of the form
37
+ #form.fields_with(:name => "category").first.options.each do |option|
38
+ # option.select if option.value.to_s == "3"
39
+ #end
40
+ # b/c of malformedness...
41
+ form["category"] = "3"
42
+ form["url"] = url
43
+ form["phase"] = "2"
44
+ form["randkey"] = page.parser.css("input[@name='randkey']").first["value"]
45
+ form["id"] = page.parser.css("input[@name='id']").first["value"]
46
+
47
+ form["tags"] = token[:tags] # comma separated with space
48
+
49
+ iframe_url = page.parser.css("noscript iframe").first["src"]
50
+ params = iframe_url.split("?").last
51
+ captcha_iframe = agent.click(page.iframes.first)
52
+ captcha_form = captcha_iframe.forms.first
53
+ captcha_image = captcha_iframe.parser.css("img").first["src"]
54
+ # open browser with captcha image
55
+ system("open", "http://api.recaptcha.net/#{captcha_image}")
56
+ # enter captcha response in terminal
57
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
58
+ captcha_form["recaptcha_response_field"] = captcha_says
59
+ # submit captcha
60
+ captcha_form.action = "http://www.google.com/recaptcha/api/noscript?#{params}"
61
+ captcha_response = captcha_form.submit
62
+ # grab secret
63
+ captcha_response = captcha_response.parser.css("textarea").first.text
64
+
65
+ form["recaptcha_challenge_field"] = captcha_response
66
+ form["recaptcha_response_field"] = "manual_challenge"
67
+ page = form.submit
68
+
69
+ unless debug?
70
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
71
+ page = form.submit
72
+ end
73
+
74
+ true
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ module Ubiquitously
2
+ module Flikode
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://flikode.com/login")
6
+ form = page.form_with(:name => "login")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "http://flikode.com/login")
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://flikode.com/snippet")
18
+ form = page.form_with(:name => "snippet")
19
+
20
+ form["title"] = token[:title]
21
+ form["description"] = token[:description]
22
+ form["tags"] = token[:tags]
23
+
24
+ form.field_with(:name => "language").options.each do |option|
25
+ option.select if option.text.to_s.strip.downcase =~ /#{format}/
26
+ end
27
+
28
+ form.radiobuttons_with(:name => "choose").last.check
29
+
30
+ form["snippet"] = token[:body]
31
+
32
+ page = form.submit
33
+
34
+ true
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module Friendfeed
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,52 @@
1
+ module Ubiquitously
2
+ module Gist
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://gist.github.com/login")
6
+ form = page.form_with(:action => "/session")
7
+ form["login"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "https://gist.github.com/session")
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ validates_presence_of :format, :extension
17
+
18
+ def tokenize
19
+ super.merge(
20
+ # make sure we have the extension
21
+ :title => self.title.gsub(/(?:\.#{self.extension})?$/, ".#{self.extension}")
22
+ )
23
+ end
24
+
25
+ def create
26
+ page = agent.get("http://gist.github.com/")
27
+ form = page.form_with(:action => "/gists")
28
+
29
+ form.field_with(:name => "file_ext[gistfile1]").options.each do |option|
30
+ if format == extension || format == option.text.to_s.downcase.strip
31
+ option.select
32
+ break
33
+ end
34
+ end
35
+
36
+ form["file_name[gistfile1]"] = token[:title]
37
+ form["file_contents[gistfile1]"] = token[:description]
38
+
39
+ if public?
40
+ button = form.buttons.last
41
+ else
42
+ form["action_button"] = "private"
43
+ button = form.buttons.first
44
+ end
45
+
46
+ page = form.submit(button)
47
+
48
+ true
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module Ubiquitously
2
+ module GoogleBuzz
3
+ class Account < Ubiquitously::Service::Account
4
+ end
5
+
6
+ class Post < Ubiquitously::Service::Post
7
+ validates_presence_of :url, :title, :description, :tags
8
+
9
+ def save(options = {})
10
+ return false unless valid?
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Ubiquitously
2
+ module Identica
3
+ class Account < Ubiquitously::Service::Account
4
+ end
5
+
6
+ class Post < Ubiquitously::Service::Post
7
+ validates_presence_of :url, :title, :description, :tags
8
+
9
+ def save(options = {})
10
+ return false unless valid?
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module JumpTags
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,27 @@
1
+ module Ubiquitously
2
+ module Kailoon
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ return true
6
+ end
7
+ end
8
+
9
+ class Post < Ubiquitously::Service::Post
10
+ def create
11
+ page = agent.get("http://kailoon.com/web-design-news/")
12
+ form = page.forms.detect { |form| form.form_node["id"] == "commentform" }
13
+
14
+ # weird, but this is how they're doing it
15
+ form["author"] = title
16
+ form["url"] = url
17
+ form["email"] = user.email
18
+ # 200 word max
19
+ form["comment"] = description
20
+
21
+ page = form.submit
22
+
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module Ubiquitously
2
+ module MetaFilter
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://login.metafilter.com/")
6
+ form = page.forms.first
7
+ form["user_name"] = username
8
+ form["user_pass"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "https://login.metafilter.com/logging-in.mefi")
12
+ end
13
+ end
14
+
15
+ # You cannot post to the front page at this time.
16
+ # This can be due to one of several things.
17
+ # You may not have been a member long enough (1 week),
18
+ # you may not have posted enough comments (at least 3),
19
+ # or you may have already posted a link in the past 24 hours.
20
+ class Post < Ubiquitously::Service::Post
21
+ def create
22
+ page = agent.get("http://www.metafilter.com/")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,94 @@
1
+ module Ubiquitously
2
+ module Mixx
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("https://www.mixx.com/")
6
+ form = page.form_with(:action => "https://www.mixx.com/save_login")
7
+ form["user[loginid]"] = username
8
+ form["user[password]"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.body !~ /login was unsuccessful/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://www.mixx.com/submit")
18
+ form = page.form_with(:action => "http://www.mixx.com/submit/step2")
19
+ form["thingy[page_url]"] = token[:url]
20
+ page = form.submit
21
+
22
+ already_submitted = page.parser.css(".flash.notice").first.text rescue ""
23
+ if (already_submitted =~ /already submitted/i)
24
+ form = page.forms.detect { |form| form.form_node["class"] =~ /vote-for/ }
25
+ form.submit
26
+
27
+ form = page.forms.detect { |form| form.form_node["id"] == "thingy_comment_form" }
28
+ form["comment[body]"] = token[:description]
29
+ form.submit
30
+ else
31
+ # last page
32
+ form = page.form_with(:action => "http://www.mixx.com/submit/save")
33
+
34
+ # captcha
35
+ iframe_url = page.parser.css("li.captcha iframe").first["src"]
36
+ params = iframe_url.split("?").last
37
+ captcha_iframe = agent.click(page.iframes.first)
38
+ captcha_form = captcha_iframe.forms.first
39
+ captcha_image = captcha_iframe.parser.css("img").first["src"]
40
+ # open browser with captcha image
41
+ system("open", "http://api.recaptcha.net/#{captcha_image}")
42
+ # enter captcha response in terminal
43
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
44
+ captcha_form["recaptcha_response_field"] = captcha_says
45
+ # submit captcha
46
+ captcha_form.action = "http://www.google.com/recaptcha/api/noscript?#{params}"
47
+ captcha_response = captcha_form.submit
48
+ # grab secret
49
+ captcha_response = captcha_response.parser.css("textarea").first.text
50
+
51
+ # submit post
52
+ form = page.form_with(:action => "http://www.mixx.com/submit/save")
53
+ form["thingy[title]"] = token[:title]
54
+ form["thingy[description]"] = token[:description]
55
+ form["thingy[new_tags]"] = token[:tags]
56
+ form["recaptcha_challenge_field"] = captcha_response
57
+ form["recaptcha_response_field"] = captcha_says
58
+
59
+ form.submit
60
+ end
61
+
62
+ true
63
+ end
64
+
65
+ class << self
66
+ def find(options = {})
67
+ records = []
68
+ user = options[:user]
69
+ user_url = "http://www.mixx.com/feeds/users/#{user.username_for(self)}"
70
+ xml = Nokogiri::XML(open(user_url).read)
71
+ urls = url_permutations(options[:url])
72
+
73
+ xml.css("item").each do |node|
74
+ title = node.css("title").first.text
75
+ url = node.xpath("mixx:source", {"mixx" => "http://www.mixx.com/mixxrss/"}).first.text
76
+ description = node.css("description").first.text
77
+ service_url = node.css("link").first.text
78
+ record = new(
79
+ :title => title,
80
+ :url => url,
81
+ :description => description,
82
+ :service_url => service_url,
83
+ :user => user
84
+ )
85
+ return record if urls.include?(record.url)
86
+ records << record
87
+ end
88
+
89
+ options[:url] ? nil : records
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end