ubiquitously 0.0.1.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -14,37 +14,242 @@ Fill out `test/config.yml` with your credentials for the different services, the
14
14
 
15
15
  rake test
16
16
 
17
- ### Register for the services you haven't already
18
-
19
- First edit the config file with a username, password, and other fields that all the systems might have. Then run this
20
-
21
- rake ubiquitously:me
22
-
23
17
  ### Automatically Post to Services
24
18
 
25
19
  require 'rubygems'
26
20
  require 'ubiquitously'
27
21
 
28
- # dzone
29
- Ubiquitously::Dzone::Post.create(
30
- :title => "A Dzone Post!",
31
- :description => "Dzone does not let you edit or delete posts once you submit them, so be careful!",
32
- :tags => ["dzone", "web 2.0"]
22
+ user = Ubiquitously::User.new(
23
+ :username => "viatropos",
24
+ :name => "Lance Pollard",
25
+ :email => "lancejpollard@gmail.com",
26
+ :cookies_path => "_cookies.yml"
27
+ )
28
+ post = Ubiquitously::Post.new(
29
+ :url => "http://postable.com",
30
+ :title => "An Interesting Post!",
31
+ :description => "This is one of those rare things on the web...",
32
+ :tags => ["writing", "programming", "javascript", "html", "ruby on rails"],
33
+ :user => user
33
34
  )
35
+ post.save("stumbleupon", "delicious", "dzone", "digg", "diigo", "reddit", "tumblr", "mixx")
36
+
37
+ ## Command-line
38
+
39
+ You can post to any of these services (even via oauth) completely from the command line.
40
+
41
+ u.me post twitter "Check out xyz!"
42
+
43
+ The anatomy of a command is this:
44
+
45
+ u.me post [services] [title] [options]
46
+
47
+ The `[services]` are a list of services you want this command to post to, and the `[title]` is whatever follows (in single/double quotes). The following will post to Twitter, Tumblr, and Posterous:
48
+
49
+ u.me post twitter tumblr posterous "Managing multiple interfaces"
34
50
 
51
+ You can get more precise by specifying options:
52
+
53
+ - `-l`: label, aka the Post "title"
54
+ - `-d`: description
55
+ - `-u`: url
56
+ - `-t`: tags (`comma,separated,without,any-spaces`)
57
+ - `-U`: username for the service
58
+ - `-P`: password for the service
59
+
60
+ So you can write a command like this:
61
+
62
+ u.me post digg "Oauth on the Command line!?" -d "You can now use Oauth from the command line" -t "oauth, ruby, unix" -u "http://ubiquitously.me"
63
+
64
+ Ubiquitously will save your login data (cookies, secrets, tokens, and params) in `~/.u.me`. You can open those files and edit them (add passwords, app keys, etc.) with these commands:
65
+
66
+ u.me cookies
67
+ u.me secrets
68
+ u.me tokens
69
+ u.me params
70
+
71
+ ## How it thinks
72
+
73
+ It treats everything as a `Post`. A post has these properties:
74
+
75
+ - `title`: Name of the post/file/content
76
+ - `url`: Url to the post
77
+ - `description`: Description/summary/comment for the post. Ranges from 50-1000 characters. Most services only allow plain, but some (code snippets, and tumblr) allow html or code.
78
+ - `tags`: Array of lowercased tags. Formats tags how services want them (e.g. comma separated vs. dashed). Applies tag limits if necessary. These are user-defined.
79
+ - `categories`: Category for the post. Most services allow 1 category, some up to 4. These are specific to the service.
80
+ - `vote`: Vote for the post, either "up", "down", or "none" (or 1, 0, -1). Only if applicable to the service.
81
+ - `rating`: Rating for the post, 1-5, if applicable.
82
+ - `privacy`: Whether the service is public or private (0 || "public", 1 || "private")
83
+ - `state`: Status of the post, either "published", "draft", "submitted", or "queued".
84
+ - `kind`: The type of post, either post, link, quote, comment, image, video, audio, or answer.
85
+ - `format`: The format of your post content, either "plain", "html", "markdown", "textile", or any code (ruby, c, php, etc.).
86
+ - `service`: This is generated from the class, e.g. "digg".
87
+ - `service_url`: The url the service provides to the post.
88
+
89
+ Each service requires different things, which are determined by the `validates_presence_of` declaration for each class. Conceptually, you can divide the services into these categories:
90
+
91
+ 1. Microblogging (twitter, yahoo meme, google buzz, identica)
92
+ 2. Tumblelogging (tumblr, posterous)
93
+ 3. Blogging (large posts)
94
+ 4. Bookmarking (delicious, diigo, mixx, newsvine, reddit, digg...)
95
+ 5. Code Sharing (gist, snipplr, dzone snippets, snipt, flikode, smipple)
96
+
35
97
  ## How it works
36
98
 
37
- Everything is built around [Mechanize](http://mechanize.rubyforge.org/mechanize/GUIDE_rdoc.html) and [Nokogiri](http://nokogiri.org/tutorials/parsing_an_html_xml_document.html), both led by [Aaron Patterson](http://tenderlovemaking.com/).
99
+ Everything is built around [Mechanize](http://mechanize.rubyforge.org/mechanize/GUIDE_rdoc.html) and [Nokogiri](http://nokogiri.org/tutorials/parsing_an_html_xml_document.html), both led by [Aaron Patterson](http://tenderlovemaking.com/) (watch [Yehuda's "How to do the Impossible video"](http://www.youtube.com/watch?v=mo-lMdQMsdw)).
38
100
 
39
101
  Many social bookmarking services do not have API's in order to prevent spammers from ruining their system. But what about for those of us that actually create content several times a day and want automation? We're out of luck.
40
102
 
41
103
  So Ubiquitously creates a simple, RESTful API around some services I need to publish to now, and hopefully it will grow as you guys need more. The goal is to be semi-low-level and not to provide a full featured api to a service, as some services already have very well-done API's in Ruby.
42
104
 
43
- ## Other Possible Services (and Resources)
105
+ ## Why
106
+
107
+ Currently there's plenty of services to post about yourself: ping.fm, onlywire, posterous... But what if you want to do the same for other people? You're left having to go to the page and click one of their social buttons, and filling out the form. No way I'm filling out more than one for a page. This solves that problem, making it so you can post someone else's site to a million places just like yours, helping you build a community.
108
+
109
+ ## What you should be doing...
110
+
111
+ ### Posting in Forums
112
+
113
+ - Comment in the forums
114
+
115
+ ### Adding to Article Directories
116
+
117
+ - Delicious
118
+
119
+ ### Guest Posting
120
+
121
+ - Envato
122
+
123
+ ### Publishing Documents
124
+
125
+ - Scribd
126
+
127
+ ### Contributing Code
128
+
129
+ - snippets, github
130
+
131
+ ### Sharing and Tagging
132
+
133
+ - Share others' content to stumbleupon, delicious, digg, diigo, reddit, tumblr, twitter, mixx, and identica.
134
+ - Tag other's posts on stumbleupon, delicious, digg, diigo, and reddit.
135
+ - Stumble other peoples posts that link to you. You'll benefit them and yourself.
136
+ - Write 2-3 sentences to describe each thing you post. So if you can share 10 things a day, that's 20-30 sentences.
137
+
138
+ ### Commenting on Blogs
139
+
140
+ - Comment on other people's blogs
141
+
142
+ ## What you should _not_ be doing...
143
+
144
+ ### Self Promoting
145
+
146
+ - Only posting your content, you will get banned from the sites.
147
+
148
+ ### Spamming
149
+
150
+ - Posting just the default description to all the sites
151
+ - Posting too much
152
+
153
+ ## Tips and Resources
154
+
155
+ - [http://www.highrevenue.com/free-website-traffic/critique-of-50-top-ways-to-drive-traffic-to-your-site](http://www.highrevenue.com/free-website-traffic/critique-of-50-top-ways-to-drive-traffic-to-your-site)
156
+ - [http://www.highrevenue.com/linkbuilding-techniques/make-link-building-the-cornerstone-of-you-daily-activities](http://www.highrevenue.com/linkbuilding-techniques/make-link-building-the-cornerstone-of-you-daily-activities)
157
+ - [http://hubpages.com/hub/viatropos](http://hubpages.com/hub/viatropos)
158
+ - [http://www.mybloglog.com/](http://www.mybloglog.com/)
159
+ - [http://www.doshdosh.com/a-comprehensive-guide-to-stumbleupon-how-to-build-massive-traffic-to-your-website-and-monetize-it/](http://www.doshdosh.com/a-comprehensive-guide-to-stumbleupon-how-to-build-massive-traffic-to-your-website-and-monetize-it/)
160
+ - [http://www.thedesigncubicle.com/2009/12/websites-to-submit-your-design-articles-that-produce-heavy-traffic/](http://www.thedesigncubicle.com/2009/12/websites-to-submit-your-design-articles-that-produce-heavy-traffic/)
161
+ - [http://www.warriorforum.com/](http://www.warriorforum.com/)
162
+ - [http://lifehacker.com/5509815/how-to-declutter-and-streamline-your-google-reader-inbox](http://lifehacker.com/5509815/how-to-declutter-and-streamline-your-google-reader-inbox)
163
+ - [http://www.netvibes.com/](http://www.netvibes.com/)
164
+ - [http://www.noodlesoft.com/hazel.php](http://www.noodlesoft.com/hazel.php)
165
+ - [http://www.webdesignerdepot.com/2010/07/30-places-to-submit-your-website-designs/](http://www.webdesignerdepot.com/2010/07/30-places-to-submit-your-website-designs/)
166
+ - [http://knowem.com/](http://knowem.com/)
167
+ - [hriscredendino.com/](hriscredendino.com/)
168
+ - [http://www.networkworld.com/news/2010/080210-social-media-sucks-up-23.html](http://www.networkworld.com/news/2010/080210-social-media-sucks-up-23.html)
169
+ - [http://opensource.newscloud.com](http://opensource.newscloud.com)
170
+ - [http://www.doshdosh.com/list-of-social-media-news-websites/](http://www.doshdosh.com/list-of-social-media-news-websites/)
171
+ - [http://popurls.com/](http://popurls.com/)
172
+ - [http://www.webdesignerdepot.com/2010/07/30-places-to-submit-your-website-designs/](http://www.webdesignerdepot.com/2010/07/30-places-to-submit-your-website-designs/)
173
+ - [http://www.shareaholic.com/](http://www.shareaholic.com/)
174
+
175
+ > Linkbuilding is not a sprint... it is a MARATHON!
176
+
177
+ 1. Get a bunch of feeds
178
+ 2. Read the feeds
179
+ 3. Share the feeds
180
+
181
+ ## Todo
182
+
183
+ - find most appropriate tags for each service
184
+ - slideshare
185
+ - if submission already exists (digg, dzone, reddit...), then make description a comment and digg it.
186
+ - validations for each service (description wordcount, num tags, categories, title)
187
+ - who can post (is it for just me or for other people)?
188
+ - programmers_heaven, meta_filter, propeller, sharebrain, shoutwire, sphinn, stumpedia, web_blend, who_freelance, youblr, zabox
189
+ - Find image on page for display
190
+ - logging at stages in the process
191
+ - addthis-like javascript bookmarking tool
192
+ - flow:
193
+ - content type: video, image, post, status
194
+ - edit
195
+ - sumbit
196
+ - each needs to check to see if post already exists
197
+ - handle categories in a generic way
198
+ - handle captchas
199
+ - if this is actually useful, maybe creating accounts programmatically
200
+ - optimize login, i could probably skip the entire "parse form" section and just do a raw post.
201
+ - I don't want to support _every_ service because most of them are spammy or are not used much lately. Let's keep it clean here. Some services are also invite only and are in very very specific niches outside my realm. If you would like to support them, feel free to fork and customize.
202
+
203
+ <cite>copyright @viatropos 2010</cite>
204
+
205
+ ## Future additions
206
+
207
+ - http://www.noupe.com/
208
+ - mashable
209
+ - smashing-magazine
210
+ - tripwire
211
+ - http://www.instantshift.com/user-submitted-news/
212
+ - http://designm.ag/submit-news/
213
+ - http://speckyboy.com/designnews/design-news-submission-form/
214
+ - http://net.tutsplus.com/link-feed/#add
215
+ - http://qik.com/
216
+ - http://www.associatedcontent.com/
217
+ - http://inboundmarketing.com
218
+ - http://clipmarks.com
219
+ - http://www.addurl.nu/
220
+ - http://blog.sponsoredreviews.com/?p=47
221
+ - http://www.metamags.com/
222
+ - http://www.developersniche.com/
223
+ - http://add.io/
224
+ - http://www.arto.com/section/frontpage/
225
+ - https://www.google.com/bookmarks/l
226
+ - amazon wishlist
227
+ - netvibes
228
+ - evernote
229
+ - http://www.evri.com/
230
+ - http://pinboard.in
231
+ - http://weheartit.com/about
232
+ - http://www.soup.io/
233
+ - http://izeby.com/
234
+ - http://linkmarking.com/
235
+ - yahoo meme
236
+ - reddit, digg, diigo, and mixx still don't work
237
+ - diigo doesn't work because cookie expires. create mechanize to re-login if cookie doesn't work
238
+ - evernote
239
+ - http://www.rubyflow.com
240
+
241
+ ## Lists
242
+
243
+ - http://www.digalist.com
244
+ - listiki.com
245
+ - tipbo.com
246
+
247
+ ## Tips from out there
248
+
249
+ Ask yourself the following questions about the linkability of your content:
250
+
251
+ - Am I Digging this because I want others to see it, and pressing a single button is an easy way for me to say "this is cool?"
252
+ - Or am I Digging this because People need to know about this, because they can’t live without it or because without it they would be out of the loop.
253
+ - Is it possible that my information is so new and/or informative that I will actually become an authority on this information, or serve as a reference for others interested in writing about similar content?
44
254
 
45
- - [http://www.iwoodpecker.com/collection-of-70-best-social-bookmarking-sites-with-pr-and-alexa/](http://www.iwoodpecker.com/collection-of-70-best-social-bookmarking-sites-with-pr-and-alexa/)
46
- - buzz.yahoo.com
47
- - http://www.wikio.com/about-us
48
- - http://designbump.com/
49
- - http://scriptandstyle.com/submit
50
- - http://www.stumpedia.com/submitlink.php
255
+ > It is only one step more to make it so we fully create all the user accounts if they don't exist on all the services
data/Rakefile CHANGED
@@ -5,18 +5,26 @@ require 'rake/gempackagetask'
5
5
  # http://docs.rubygems.org/read/chapter/20
6
6
  spec = Gem::Specification.new do |s|
7
7
  s.name = "ubiquitously"
8
- s.version = "0.0.1.6"
8
+ s.version = "0.1.0"
9
9
  s.author = "Lance Pollard"
10
- s.summary = "Ubiquitously: Making it easy for you to be everywhere, even if there's no API"
10
+ s.summary = "Ubiquitously: Social Publishing to everywhere from anywhere, even if there's no API"
11
11
  s.homepage = "http://github.com/viatropos/ubiquitously"
12
12
  s.email = "lancejpollard@gmail.com"
13
- s.description = "Making it easy for you to be everywhere, even if there's no API"
13
+ s.description = "Social Publishing Rubygem"
14
14
  s.has_rdoc = true
15
15
  s.rubyforge_project = "ubiquitously"
16
16
  s.platform = Gem::Platform::RUBY
17
- s.files = %w(README.markdown Rakefile init.rb MIT-LICENSE) + Dir["{lib,rails,test}/**/*"] - Dir["test/tmp"]
17
+ s.files = %w(README.markdown Rakefile init.rb MIT-LICENSE) + Dir["{lib,rails,test,bin}/**/*"] - Dir["test/tmp"]
18
18
  s.require_path = "lib"
19
+ s.executables = ["u.me"]
20
+ s.add_dependency("json")
19
21
  s.add_dependency("activesupport", ">= 2.3.5")
22
+ s.add_dependency("mechanize")
23
+ s.add_dependency("highline")
24
+ s.add_dependency("rack")
25
+ s.add_dependency("httparty")
26
+ s.add_dependency("activemodel")
27
+ s.add_dependency("passport")
20
28
  end
21
29
 
22
30
  Rake::GemPackageTask.new(spec) do |pkg|
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../lib/ubiquitously'
3
+
4
+ Ubiquitously.run(ARGV)
@@ -1,38 +1,70 @@
1
1
  require 'rubygems'
2
2
  require 'open-uri'
3
3
  require 'cgi'
4
+ require 'rack/utils'
4
5
  require 'yaml'
5
6
  require 'json'
6
- require 'nokogiri'
7
7
  require 'mechanize'
8
8
  require 'highline/import'
9
9
  require 'logger'
10
+ require 'httparty'
10
11
  require 'active_support'
11
12
  require 'active_model'
13
+ require 'passport'
12
14
 
13
15
  this = File.dirname(__FILE__)
14
- require "#{this}/ext"
15
- Dir["#{this}/ubiquitously/mixins/*"].each { |c| require c }
16
- require "#{this}/ubiquitously/base"
17
16
 
18
17
  module Ubiquitously
19
18
  class SettingsError < StandardError; end
20
19
  class AuthenticationError < StandardError; end
21
20
  class DuplicateError < StandardError; end
22
-
21
+ class RecordInvalid < StandardError; end
22
+ class CommandInvalid < StandardError; end
23
+
23
24
  class << self
24
- attr_accessor :config
25
+ attr_accessor :config, :logger
26
+
27
+ def run(args)
28
+ command = args.shift
29
+ if command =~ /(secrets|tokens|cookies|credentials)/
30
+ system("open", File.expand_path("~/.u.me/#{$1}.yml"))
31
+ exit
32
+ end
33
+ unless command =~ /(?:post|user)/
34
+ message = "\nUbiquitously command must be for either 'post' or 'user', e.g.:\n"
35
+ message << "u.me post twitter 'Working with Rails today...'"
36
+ raise CommandInvalid.new(message)
37
+ end
38
+ "Ubiquitously::Command::#{command.camelize}".constantize.run(args)
39
+ end
25
40
 
26
41
  def configure(value)
27
42
  self.config = value.is_a?(String) ? YAML.load_file(value) : value
28
43
  end
29
44
 
45
+ def logger
46
+ unless @logger
47
+ @logger = Logger.new(STDOUT)
48
+ @logger.level = Logger::INFO
49
+ end
50
+
51
+ @logger
52
+ end
53
+
54
+ def debug?
55
+ logger.debug?
56
+ end
57
+
30
58
  def key(path)
31
59
  result = self.config
32
60
  path.to_s.split(".").each { |node| result = result[node.to_s] if result }
33
61
  result.to_s
34
62
  end
35
63
 
64
+ def include?(service)
65
+ services.include?(service)
66
+ end
67
+
36
68
  def credentials(service)
37
69
  result = key(service)
38
70
  unless result && result.has_key?("key") && result.has_key?("secret")
@@ -40,7 +72,24 @@ module Ubiquitously
40
72
  end
41
73
  result
42
74
  end
75
+
76
+ def services
77
+ Dir.entries(File.dirname(__FILE__) + '/ubiquitously/services')[2..-1].collect do |service|
78
+ service = File.basename(service).split(".").first
79
+ end
80
+ end
43
81
  end
44
82
  end
45
83
 
46
- Dir["#{this}/ubiquitously/*"].each { |c| require c unless File.directory?(c) }
84
+ Dir["#{this}/ubiquitously/extensions/*"].each { |c| require c }
85
+ Dir["#{this}/ubiquitously/models/*"].each { |c| require c unless File.directory?(c) }
86
+ Dir["#{this}/ubiquitously/services/*"].each { |c| require c unless File.directory?(c) }
87
+ Dir["#{this}/ubiquitously/support/*"].each { |c| require c unless File.directory?(c) }
88
+ Dir["#{this}/ubiquitously/commands/*"].each { |c| require c unless File.directory?(c) }
89
+
90
+ overrides = Dir["#{this}/ubiquitously/services/*"].map do |file|
91
+ name = File.basename(file).split(".").first.camelize
92
+ ["Ubiquitously::#{name}::Account".constantize, "Ubiquitously::#{name}::Post".constantize]
93
+ end.flatten
94
+
95
+ SubclassableCallbacks.override(*overrides)
@@ -0,0 +1,118 @@
1
+ module Ubiquitously
2
+ module Command
3
+ class Base
4
+ class << self
5
+ def run(args)
6
+ new(args).run
7
+ end
8
+ end
9
+
10
+ attr_accessor :services, :attributes
11
+
12
+ def write(to, content = "")
13
+ File.open(to, "w+") { |file| file.puts content }
14
+ end
15
+
16
+ def configure(folder)
17
+ Dir.mkdir(folder) unless File.exists?(folder)
18
+ secrets_path = File.join(folder, "secrets.yml")
19
+ tokens_path = File.join(folder, "tokens.yml")
20
+
21
+ # usernames and passwords for post services
22
+ unless File.exists?(secrets_path)
23
+ secrets = "# #{secrets_path}, in your home directory\n"
24
+ secrets << "# write your username and passwords for the different services\n"
25
+ secrets << "# as necessary.\n\n"
26
+ Ubiquitously.services.each do |service|
27
+ secrets << "#{service}:\n"
28
+ secrets << " key: your_username\n"
29
+ secrets << " secret: your_password\n"
30
+ end
31
+ write(secrets_path, secrets)
32
+ system("open", secrets_path)
33
+ puts "Please configure your service username and passwords and rerun your command."
34
+ exit
35
+ end
36
+
37
+ Ubiquitously.configure(secrets_path)
38
+
39
+ # oauth keys and secrets from services
40
+ unless File.exists?(tokens_path)
41
+ tokens = "# #{tokens_path}, in your home directory\n"
42
+ tokens << "# Get app key/secrets from the oauth providers below\n"
43
+ tokens << "# and fill them out as desired.\n\n"
44
+ tokens << "services:\n"
45
+ Passport.services.each do |service|
46
+ tokens << " #{service}:\n"
47
+ tokens << " key: app_key\n"
48
+ tokens << " secrets: app_secret\n"
49
+ end
50
+ write(tokens_path, tokens)
51
+ system("open", tokens_path)
52
+ puts "Please configure your oauth keys and secrets and rerun your command."
53
+ exit
54
+ end
55
+
56
+ Passport.configure(tokens_path)
57
+ end
58
+
59
+ def main_folder
60
+ File.expand_path("~/.u.me")
61
+ end
62
+
63
+ def show
64
+ tmp = File.join(main_folder, "post.yml")
65
+ if File.exists?(tmp)
66
+ post = IO.read(tmp)
67
+ else
68
+ post = ""
69
+ post << "services: \n"
70
+ post << "url: \n"
71
+ post << "title: \n"
72
+ post << "description: \n"
73
+ post << "tags: \n"
74
+ write(tmp, post)
75
+ end
76
+ system("open", tmp)
77
+ require 'timeout'
78
+ begin
79
+ Timeout::timeout(30) {
80
+ puts "Will timeout in 30 seconds. Press Enter when you're ready."
81
+ STDIN.gets.chomp
82
+ self.attributes = YAML.load_file(tmp).symbolize_keys
83
+ #File.delete(tmp) if File.exists?(tmp)
84
+ # Something that should be interrupted if it takes too much time...
85
+ }
86
+ rescue Exception => e
87
+ puts e.inspect
88
+ puts "Resubmit post with same command. Finished process executing to clean things up."
89
+ exit
90
+ end
91
+
92
+ end
93
+
94
+ def initialize(args)
95
+ configure(main_folder)
96
+ self.services = []
97
+ self.attributes = {}
98
+ show if args.blank?
99
+ self.services << args.shift while args.length > 0 && args.first !~ /^-/
100
+ self.services << attributes.delete(:services) if attributes.has_key?(:services)
101
+ self.attributes[:title] = self.services.pop unless Ubiquitously.include?(self.services.last)
102
+ self.attributes = parse_options(args, attributes)
103
+
104
+ self.attributes.each do |key, value|
105
+ self.send("#{key.to_s}=", value) if self.respond_to?(key)
106
+ end
107
+ end
108
+
109
+ def parse_options(attributes)
110
+
111
+ end
112
+
113
+ def run
114
+
115
+ end
116
+ end
117
+ end
118
+ end