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,108 @@
1
+ module Ubiquitously
2
+ module Command
3
+ class Post < Ubiquitously::Command::Base
4
+
5
+ def run
6
+ user = Ubiquitously::User.new(:storage => main_folder)
7
+ user.accountables(services) do |account|
8
+ account = account.new(
9
+ :user => user,
10
+ :username => attributes[:username] || Ubiquitously.key("#{account.service}.key"),
11
+ :password => attributes[:password] || Ubiquitously.key("#{account.service}.secret")
12
+ )
13
+ end
14
+ Ubiquitously::Post.new(attributes.merge(:user => user)).save(services)
15
+ end
16
+
17
+ def required(attributes)
18
+ missing = %w(description).delete_if { |i| !attributes[i.to_sym].blank? }
19
+ unless missing.blank?
20
+ raise CommandInvalid.new("Missing arguments for post: #{missing.join(", ")}")
21
+ end
22
+ attributes
23
+ end
24
+
25
+ def parse_options(args, attributes = {})
26
+
27
+ option_parser = OptionParser.new do |o|
28
+ o.extend Ubiquitously::Command::Post::Opts
29
+ o.options(attributes)
30
+
31
+ o.banner = "Usage: u.me [command] [service(s)] [options]\n" +
32
+ "\n" +
33
+ "Supported Commands:\n#{Ubiquitously.services.sort.join(', ')}"
34
+
35
+ o.section "Post attributes:" do
36
+ url
37
+ title
38
+ description
39
+ tags
40
+ username
41
+ password
42
+ end
43
+ end
44
+
45
+ option_parser.parse!(args)
46
+
47
+ required attributes
48
+ end
49
+
50
+ module Opts
51
+
52
+ def options(value = nil)
53
+ @options = value if value
54
+ @options
55
+ end
56
+
57
+ def section(heading, &block)
58
+ separator ""
59
+ separator heading
60
+
61
+ instance_eval(&block)
62
+ end
63
+
64
+ def url
65
+ on('-u', '--url URL', "Post url (required)") do |url|
66
+ options[:url] = url
67
+ end
68
+ end
69
+
70
+ def title
71
+ on('-l', '--title TITLE', "Post title (required)") do |title|
72
+ options[:title] = title
73
+ end
74
+ end
75
+
76
+ def tags
77
+ on('-t', '--tags TAGS', "Post tags (required)") do |tags|
78
+ options[:tags] = tags.split(/,(?:\s+)?/)
79
+ end
80
+ end
81
+
82
+ def description
83
+ on('-d', '--description DESCRIPTION', "Post description (required)") do |description|
84
+ options[:description] = description
85
+ end
86
+ end
87
+
88
+ def username
89
+ on('-U', '--username [username]', "Username for service") do |username|
90
+ options[:username] = username
91
+ end
92
+ end
93
+
94
+ def password
95
+ on('-P', '--password [password]', "Password for service") do |password|
96
+ options[:password] = password
97
+ end
98
+ end
99
+
100
+ def help
101
+ on_tail("-h", "--help", "Show this message") do
102
+ exit
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,111 @@
1
+ module Ubiquitously
2
+ module Command
3
+ class User < Ubiquitously::Command::Base
4
+
5
+ def run
6
+ Ubiquitously::User.new(attributes).login(services)
7
+ end
8
+
9
+ def parse_options(args)
10
+ option_parser = OptionParser.new do |o|
11
+ o.extend Ubiquitously::Opts
12
+
13
+ o.banner = "Usage: u.me [command] [service(s)] [options]\n" +
14
+ "\n" +
15
+ "Supported Commands:\n#{SUPPORTED_COMMANDS.sort.join(', ')}"
16
+
17
+ o.section "Getting started:" do
18
+ tutorial
19
+ end
20
+
21
+ o.section "Authorization options:" do
22
+ username
23
+ password
24
+ consumer_key
25
+ consumer_secret
26
+ access_token
27
+ password
28
+ end
29
+
30
+ o.section "Common options:" do
31
+ trace
32
+ data
33
+ host
34
+ quiet
35
+ disable_ssl
36
+ request_method
37
+ help
38
+ end
39
+ end
40
+
41
+ option_parser.parse!(args)
42
+ end
43
+
44
+ module Opts
45
+
46
+ def section(heading, &block)
47
+ separator ""
48
+ separator heading
49
+
50
+ instance_eval(&block)
51
+ end
52
+
53
+ def tutorial
54
+ on('-T', '--tutorial', "Narrative overview of how to get started using Ubiquitously.me") do
55
+ CLI.puts IO.read("README.markdown")
56
+ exit
57
+ end
58
+ end
59
+
60
+ def consumer_key
61
+ on('-c', '--consumer-key [key]', "Your consumer key (required)") do |key|
62
+ options.consumer_key = key ? key : CLI.prompt_for('Consumer key')
63
+ end
64
+ end
65
+
66
+ def consumer_secret
67
+ on('-s', '--consumer-secret [secret]', "Your consumer secret (required)") do |secret|
68
+ options.consumer_secret = secret ? secret : CLI.prompt_for('Consumer secret')
69
+ end
70
+ end
71
+
72
+ def username
73
+ on('-u', '--username [name]', 'Your access token') do |name|
74
+ options.username = name
75
+ end
76
+ end
77
+
78
+ def password
79
+ on('-p', '--password', "Your token secret") do |secret|
80
+ options.password = secret
81
+ end
82
+ end
83
+
84
+ def username
85
+ on('-u', '--username [username]', 'Username of account to authorize (required)') do |username|
86
+ options.username = username
87
+ end
88
+ end
89
+
90
+ def password
91
+ on('-p', '--password [password]', 'Password of account to authorize (required)') do |password|
92
+ options.password = password ? password : CLI.prompt_for('Password')
93
+ end
94
+ end
95
+
96
+ def quiet
97
+ on('-q', '--quiet', 'Suppress all output (default: output is printed to STDOUT)') do |quiet|
98
+ options.output = StringIO.new
99
+ end
100
+ end
101
+
102
+ def help
103
+ on_tail("-h", "--help", "Show this message") do
104
+ CLI.puts self
105
+ exit
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'active_model'
3
+
4
+ # use this if you want to create before and after filters around a commonly used
5
+ # method, but still want to define the method in subclasses.
6
+ module SubclassableCallbacks
7
+ def self.included(base)
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ attr_accessor :subclassable_callbacks
13
+
14
+ def subclassable_callbacks(*methods)
15
+ @subclassable_callbacks ||= []
16
+
17
+ unless methods.empty?
18
+ @subclassable_callbacks = @subclassable_callbacks.concat(methods).flatten.compact.map(&:to_sym).uniq
19
+ define_model_callbacks *methods
20
+ class_eval do
21
+ methods.each do |variable|
22
+ define_method "implementation_#{variable.to_s}" do; end
23
+ define_method variable do
24
+ send("_run_#{variable.to_s}_callbacks") do
25
+ send("implementation_#{variable.to_s}")
26
+ end
27
+ end
28
+ alias_method "superclass_#{variable.to_s}", variable
29
+ end
30
+ end
31
+ end
32
+
33
+ @subclassable_callbacks
34
+ end
35
+ end
36
+
37
+ # ObjectSpace.each_object(Class).to_a for all of them
38
+ def self.override(*classes)
39
+ classes = ObjectSpace.each_object(Class).to_a if classes.blank?
40
+ classes.flatten.each do |object|
41
+ if object.ancestors.include?(SubclassableCallbacks)
42
+ object.class_eval do
43
+ methods = object.subclassable_callbacks
44
+ last_index = object.superclass.ancestors.index(SubclassableCallbacks)
45
+ if last_index && last_index > 0
46
+ superclasses = object.superclass.ancestors[0..last_index - 1]
47
+ superclass_methods = superclasses.select do |clazz|
48
+ clazz.respond_to?(:subclassable_callbacks)
49
+ end.map(&:subclassable_callbacks)
50
+ methods = methods.concat(superclass_methods).flatten.uniq
51
+ end
52
+ methods.each do |name|
53
+ next unless object.overrides?(name)
54
+ alias_method "subclass_#{name}", "#{name}"
55
+ alias_method "implementation_#{name}", "subclass_#{name}"
56
+ alias_method "#{name}", "superclass_#{name}"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,88 @@
1
+ # thanks to the answer here:
2
+ # http://stackoverflow.com/questions/3488203/how-do-i-see-where-in-the-class-hierarchy-a-method-was-defined-and-overridden-in
3
+ class Object
4
+ def self.overridden_methods(parent_class = Object, within_tree = true)
5
+ if within_tree
6
+ defined_methods = ancestors[0..ancestors.index(parent_class) - 1].map { |object| object.instance_methods(false) }.flatten.uniq
7
+ parent_methods = superclass.instance_methods
8
+ else
9
+ defined_methods = instance_methods(false)
10
+ parent_methods = parent_class.instance_methods
11
+ end
12
+ defined_methods & parent_methods
13
+ end
14
+
15
+ def overridden_methods(parent_class = Object, within_tree = true)
16
+ self.class.overridden_methods(parent_class, within_tree)
17
+ end
18
+
19
+ def self.overrides?(method, parent_class = Object, within_tree = true)
20
+ overridden_methods(parent_class, within_tree).include?(method.to_s)
21
+ end
22
+
23
+ def overrides?(method, parent_class = Object, within_tree = true)
24
+ self.class.overrides?(method, parent_class, within_tree)
25
+ end
26
+ end
27
+
28
+ class Hash
29
+ def recursively_symbolize_keys!
30
+ self.symbolize_keys!
31
+ self.values.each do |v|
32
+ if v.is_a? Hash
33
+ v.recursively_symbolize_keys!
34
+ elsif v.is_a? Array
35
+ v.recursively_symbolize_keys!
36
+ end
37
+ end
38
+ self
39
+ end
40
+
41
+ def symbolize_keys
42
+ inject({}) do |options, (key, value)|
43
+ options[(key.to_sym rescue key) || key] = value
44
+ options
45
+ end
46
+ end
47
+
48
+ # Destructively convert all keys to symbols.
49
+ def symbolize_keys!
50
+ self.replace(self.symbolize_keys)
51
+ end
52
+ end
53
+
54
+ class Array
55
+ def chop(separator = "", max = 40, &block)
56
+ return self if self.join(separator).length < max # opt.
57
+ result = []
58
+ self.each do |word|
59
+ break if (result.join(separator).length + word.length > max)
60
+ word = yield word if block_given?
61
+ result << word
62
+ result
63
+ end
64
+ result
65
+ end
66
+
67
+ # separator = ", ",
68
+ # max = 10_000
69
+ # quote = true|false
70
+ def taggify(space = " ", separator = ", ", max = 10_000)
71
+ quoted = !(separator =~ /\s+/).nil?
72
+ chop(separator, max) do |word|
73
+ result = word.downcase.strip.gsub(/[^a-z0-9\.]/, space).squeeze(space)
74
+ result = "\"#{result}\"" if quoted && !(result =~ /\s+/).nil?
75
+ result
76
+ end.join(separator)
77
+ end
78
+
79
+ def recursively_symbolize_keys!
80
+ self.each do |item|
81
+ if item.is_a? Hash
82
+ item.recursively_symbolize_keys!
83
+ elsif item.is_a? Array
84
+ item.recursively_symbolize_keys!
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,35 @@
1
+ class NilClass; def search(*args); []; end; end
2
+
3
+ Mechanize::Chain::PostConnectHook.class_eval do
4
+
5
+ def handle(ctx, params)
6
+ headers = params[:response].to_hash
7
+ if headers.has_key?("location")
8
+ headers["location"].each do |location|
9
+ url = URI.parse(location)
10
+ # we want mechanize to return if it sees a redirect back to localhost for facebook
11
+ if url.host == "localhost" && url.port == 4567
12
+ params[:res_klass] = Net::HTTPSuccess
13
+ end
14
+ end
15
+ end
16
+
17
+ super(ctx, params)
18
+ end
19
+
20
+ end
21
+
22
+ class Mechanize::CookieJar
23
+ public
24
+ def jar=(hash)
25
+ @jar = hash
26
+ end
27
+
28
+ def save_string
29
+ return YAML::dump(@jar)
30
+ end
31
+
32
+ def load_string(str)
33
+ @jar = YAML::load(str)
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ module Ubiquitously
2
+ class Base
3
+ include ActiveModel::Validations
4
+ extend ActiveModel::Callbacks
5
+ include ActiveModel::Serialization
6
+ include SubclassableCallbacks
7
+
8
+ def apply(attributes)
9
+ attributes.each do |key, value|
10
+ self.send("#{key.to_s}=", value) if self.respond_to?(key)
11
+ end
12
+ end
13
+
14
+ def debug?
15
+ Ubiquitously.debug?
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ module Ubiquitously
2
+ class Page < Base
3
+ attr_accessor :url, :title, :description, :tags, :image
4
+
5
+ def initialize(attributes = {})
6
+ apply attributes
7
+ end
8
+
9
+ def parse
10
+ html = Nokogiri::HTML(open(url).read)
11
+
12
+ self.title = html.xpath("//title").first.text.to_s.strip
13
+
14
+ self.description = html.xpath("//meta[@name='description']").first["content"] rescue ""
15
+ self.description.strip!
16
+
17
+ self.tags = html.xpath("//meta[@name='keywords']").first["content"] rescue ""
18
+ self.tags = self.tags.split(/,\s+/).taggify("-", ", ").split(", ")
19
+
20
+ self.image = html.xpath("//link[@rel='image_src']").first["image_src"] rescue nil
21
+ if self.image.blank?
22
+ self.image = html.xpath("//img").first["src"] rescue nil
23
+ end
24
+
25
+ self
26
+ end
27
+ end
28
+ end