twittermotion 0.0.1
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.
- data/.gitignore +5 -0
- data/Gemfile +7 -0
- data/README.md +64 -0
- data/Rakefile +11 -0
- data/TwitterMotion.gemspec +20 -0
- data/app/app_delegate.rb +47 -0
- data/lib/twittermotion.rb +15 -0
- data/lib/twittermotion/composer.rb +117 -0
- data/lib/twittermotion/pollute.rb +9 -0
- data/lib/twittermotion/twitter.rb +28 -0
- data/lib/twittermotion/user.rb +39 -0
- data/lib/twittermotion/version.rb +3 -0
- data/spec/main_spec.rb +9 -0
- metadata +107 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# TwitterMotion, a RubyMotion Wrapper
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
Sign in:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
Twitter.sign_in do |granted, ns_error|
|
9
|
+
# have fun
|
10
|
+
end
|
11
|
+
```
|
12
|
+
|
13
|
+
See accounts:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
> Twitter.accounts
|
17
|
+
=> [#<Twitter::User>]
|
18
|
+
> Twitter.accounts[0].username
|
19
|
+
=> "clayallsopp"
|
20
|
+
```
|
21
|
+
|
22
|
+
Compose a tweet:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
Twitter.accounts[0].compose(tweet: 'Hello RubyMotion!',
|
26
|
+
images: [ui_image], urls: ["http://clayallsopp.com"]) do |composer|
|
27
|
+
if composer.error
|
28
|
+
# check error.invalid_tweet/images/urls
|
29
|
+
elsif composer.cancelled?
|
30
|
+
# user didnt sent the tweet
|
31
|
+
elsif composer.done?
|
32
|
+
# user sent the tweet
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
or without a user:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
composer = Twitter::Composer.new
|
41
|
+
composer.compose(tweet: 'Hello RubyMotion!',
|
42
|
+
images: [ui_image], urls: ["http://clayallsopp.com"]) do |composer|
|
43
|
+
...
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
Grab a user's timeline:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
user.get_timeline do |hash, ns_error|
|
51
|
+
p "Timeline #{hash}"
|
52
|
+
# => [{\"coordinates\"=>nil, \"truncated\"=>false.....}, ....]
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
## Installation
|
57
|
+
|
58
|
+
1. `gem install twittermotion`
|
59
|
+
|
60
|
+
2. Add `require 'twittermotion'` to your `Rakefile`
|
61
|
+
|
62
|
+
## Pull Requests
|
63
|
+
|
64
|
+
It would be really cool if this was a fully-compatible Twitter API wrapper, so add whatever functionality you think helps!
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
$:.unshift("/Library/RubyMotion/lib")
|
2
|
+
require 'motion/project'
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
|
5
|
+
$:.unshift("./lib/")
|
6
|
+
require './lib/twittermotion'
|
7
|
+
|
8
|
+
Motion::Project::App.setup do |app|
|
9
|
+
# Use `rake config' to see complete project settings.
|
10
|
+
app.name = 'TwitterMotion'
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/twittermotion/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "twittermotion"
|
6
|
+
s.version = Twitter::VERSION
|
7
|
+
s.authors = ["Clay Allsopp"]
|
8
|
+
s.email = ["clay.allsopp@gmail.com"]
|
9
|
+
s.homepage = "https://github.com/clayallsopp/twittermotion"
|
10
|
+
s.summary = "A RubyMotion Twitter Wrapper"
|
11
|
+
s.description = "A RubyMotion Twitter Wrapper"
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split($\)
|
14
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
|
17
|
+
s.add_dependency "bubble-wrap", ">= 1.1.2"
|
18
|
+
s.add_development_dependency 'geomotion'
|
19
|
+
s.add_development_dependency 'rake'
|
20
|
+
end
|
data/app/app_delegate.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class AppDelegate
|
2
|
+
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
3
|
+
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
4
|
+
@controller = UIViewController.alloc.initWithNibName(nil, bundle:nil)
|
5
|
+
@window.rootViewController = @controller
|
6
|
+
@window.makeKeyAndVisible
|
7
|
+
|
8
|
+
Twitter.sign_in do |granted, error|
|
9
|
+
if granted
|
10
|
+
compose = UIButton.buttonWithType(UIButtonTypeRoundedRect)
|
11
|
+
compose.setTitle("Compose", forState:UIControlStateNormal)
|
12
|
+
compose.sizeToFit
|
13
|
+
@controller.view.addSubview(compose)
|
14
|
+
compose.when UIControlEventTouchUpInside do
|
15
|
+
account = Twitter.accounts[0]
|
16
|
+
account.compose(tweet: "Hello World!", urls: ["http://clayallsopp.com"]) do |composer|
|
17
|
+
p "Done? #{composer.done?}"
|
18
|
+
p "Cancelled? #{composer.cancelled?}"
|
19
|
+
p "Error #{composer.error.inspect}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
timeline = UIButton.buttonWithType(UIButtonTypeRoundedRect)
|
24
|
+
timeline.setTitle("Timeline", forState:UIControlStateNormal)
|
25
|
+
timeline.setTitle("Loading", forState:UIControlStateDisabled)
|
26
|
+
timeline.sizeToFit
|
27
|
+
timeline.frame = compose.frame.below(10)
|
28
|
+
@controller.view.addSubview(timeline)
|
29
|
+
timeline.when UIControlEventTouchUpInside do
|
30
|
+
timeline.enabled = false
|
31
|
+
account = Twitter.accounts[0]
|
32
|
+
account.get_timeline do |hash, error|
|
33
|
+
timeline.enabled = true
|
34
|
+
p "Timeline #{hash}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
else
|
38
|
+
label = UILabel.alloc.initWithFrame(CGRectZero)
|
39
|
+
label.text = "Denied :("
|
40
|
+
label.sizeToFit
|
41
|
+
label.center = @controller.view.frame.center
|
42
|
+
@controller.view.addSubview(label)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "twittermotion/version"
|
2
|
+
|
3
|
+
unless defined?(Motion::Project::Config)
|
4
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'bubble-wrap'
|
8
|
+
require 'geomotion'
|
9
|
+
|
10
|
+
Motion::Project::App.setup do |app|
|
11
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'twittermotion/*.rb')).each do |file|
|
12
|
+
app.files.unshift(file)
|
13
|
+
end
|
14
|
+
app.frameworks += ["Twitter", "Accounts"]
|
15
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Twitter
|
2
|
+
class ComposerError
|
3
|
+
attr_accessor :invalid_tweet
|
4
|
+
attr_accessor :invalid_images
|
5
|
+
attr_accessor :invalid_urls
|
6
|
+
|
7
|
+
def initialize(tweet = nil, images = nil, urls = nil)
|
8
|
+
self.invalid_tweet = tweet
|
9
|
+
self.invalid_images = images
|
10
|
+
self.invalid_urls = urls
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Composer
|
15
|
+
def self.available?
|
16
|
+
TWTweetComposeViewController.canSendTweet
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :compose_controller
|
20
|
+
attr_accessor :callback
|
21
|
+
attr_accessor :error, :result
|
22
|
+
attr_accessor :images, :urls, :tweet
|
23
|
+
|
24
|
+
def compose_controller
|
25
|
+
@compose_controller ||= TWTweetComposeViewController.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def done?
|
29
|
+
@result == TWTweetComposeViewControllerResultDone
|
30
|
+
end
|
31
|
+
|
32
|
+
def cancelled?
|
33
|
+
@result == TWTweetComposeViewControllerResultCancelled
|
34
|
+
end
|
35
|
+
|
36
|
+
def urls=(urls)
|
37
|
+
self.compose_controller.removeAllURLs
|
38
|
+
|
39
|
+
invalid_urls = []
|
40
|
+
urls ||= []
|
41
|
+
|
42
|
+
urls.each do |url|
|
43
|
+
_url = url
|
44
|
+
if _url.is_a? NSString
|
45
|
+
_url = NSURL.URLWithString(url)
|
46
|
+
end
|
47
|
+
if !self.compose_controller.addURL(_url)
|
48
|
+
invalid_urls << url
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if invalid_urls.length > 0
|
53
|
+
self.error ||= Twitter::ComposerError.new
|
54
|
+
self.error.invalid_urls = invalid_urls
|
55
|
+
end
|
56
|
+
|
57
|
+
@urls = urls
|
58
|
+
end
|
59
|
+
|
60
|
+
def images=(images)
|
61
|
+
self.compose_controller.removeAllImages
|
62
|
+
|
63
|
+
invalid_images = []
|
64
|
+
images ||= []
|
65
|
+
images.each do |ui_image|
|
66
|
+
if !self.compose_controller.addImage(ui_image)
|
67
|
+
invalid_images << ui_image
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if invalid_images.length > 0
|
72
|
+
self.error ||= Twitter::ComposerError.new
|
73
|
+
self.error.invalid_images = invalid_images
|
74
|
+
end
|
75
|
+
|
76
|
+
@images = images
|
77
|
+
end
|
78
|
+
|
79
|
+
def tweet=(tweet)
|
80
|
+
if !self.compose_controller.setInitialText(tweet)
|
81
|
+
self.error ||= Twitter::ComposerError.new
|
82
|
+
self.error.invalid_tweet = tweet
|
83
|
+
end
|
84
|
+
|
85
|
+
@tweet = tweet
|
86
|
+
end
|
87
|
+
|
88
|
+
def compose(options = {}, &compose_callback)
|
89
|
+
self.error = nil
|
90
|
+
|
91
|
+
self.tweet = options[:tweet] || self.tweet
|
92
|
+
self.images = options[:images] || self.images
|
93
|
+
self.urls = options[:urls] || self.urls
|
94
|
+
|
95
|
+
if self.error
|
96
|
+
Dispatch::Queue.main.async {
|
97
|
+
compose_callback.call(self)
|
98
|
+
}
|
99
|
+
return
|
100
|
+
end
|
101
|
+
|
102
|
+
options[:animated] = true if !options.has_key? :animated
|
103
|
+
options[:presenting_controller] ||= UIWindow.keyWindow.rootViewController
|
104
|
+
|
105
|
+
self.callback ||= lambda { |composer|
|
106
|
+
self.compose_controller.dismissModalViewControllerAnimated(true)
|
107
|
+
compose_callback.call(self)
|
108
|
+
}
|
109
|
+
self.compose_controller.completionHandler = lambda { |result|
|
110
|
+
self.result = result
|
111
|
+
self.callback.call(self)
|
112
|
+
}
|
113
|
+
|
114
|
+
options[:presenting_controller].presentModalViewController(self.compose_controller, animated: options[:animated])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Twitter
|
2
|
+
module_function
|
3
|
+
def account_store
|
4
|
+
@account_store ||= ACAccountStore.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def account_type
|
8
|
+
@account_type ||= self.account_store.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
|
9
|
+
end
|
10
|
+
|
11
|
+
def accounts
|
12
|
+
@accounts ||= self.account_store.accountsWithAccountType(account_type).collect do |ac_account|
|
13
|
+
Twitter::User.new(ac_account)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def sign_in(&block)
|
18
|
+
@sign_in_callback = block
|
19
|
+
self.account_store.requestAccessToAccountsWithType(self.account_type,
|
20
|
+
withCompletionHandler:lambda { |granted, error|
|
21
|
+
# Reset accounts
|
22
|
+
@accounts = nil
|
23
|
+
Dispatch::Queue.main.sync {
|
24
|
+
@sign_in_callback.call(granted, error)
|
25
|
+
}
|
26
|
+
})
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Twitter
|
2
|
+
class User
|
3
|
+
attr_accessor :ac_account
|
4
|
+
|
5
|
+
def initialize(ac_account)
|
6
|
+
self.ac_account = ac_account
|
7
|
+
end
|
8
|
+
|
9
|
+
def username
|
10
|
+
self.ac_account.username
|
11
|
+
end
|
12
|
+
|
13
|
+
# user.compose(tweet: 'initial tweet', images: [ui_image, ui_image],
|
14
|
+
# urls: ["http://", ns_url, ...]) do |composer|
|
15
|
+
#
|
16
|
+
# end
|
17
|
+
def compose(options = {}, &block)
|
18
|
+
@composer = Twitter::Composer.new
|
19
|
+
@composer.compose(options) do |composer|
|
20
|
+
block.call(composer)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# user.get_timeline(include_entities: 1) do |hash, ns_error|
|
25
|
+
# end
|
26
|
+
def get_timeline(options = {}, &block)
|
27
|
+
url = NSURL.URLWithString("http://api.twitter.com/1/statuses/home_timeline.json")
|
28
|
+
request = TWRequest.alloc.initWithURL(url, parameters:options, requestMethod:TWRequestMethodGET)
|
29
|
+
request.account = self.ac_account
|
30
|
+
request.performRequestWithHandler(lambda {|response_data, url_response, error|
|
31
|
+
if !response_data
|
32
|
+
block.call(nil, error)
|
33
|
+
else
|
34
|
+
block.call(BubbleWrap::JSON.parse(response_data), nil)
|
35
|
+
end
|
36
|
+
})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/main_spec.rb
ADDED
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twittermotion
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Clay Allsopp
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bubble-wrap
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.1.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.1.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: geomotion
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A RubyMotion Twitter Wrapper
|
63
|
+
email:
|
64
|
+
- clay.allsopp@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- TwitterMotion.gemspec
|
74
|
+
- app/app_delegate.rb
|
75
|
+
- lib/twittermotion.rb
|
76
|
+
- lib/twittermotion/composer.rb
|
77
|
+
- lib/twittermotion/pollute.rb
|
78
|
+
- lib/twittermotion/twitter.rb
|
79
|
+
- lib/twittermotion/user.rb
|
80
|
+
- lib/twittermotion/version.rb
|
81
|
+
- spec/main_spec.rb
|
82
|
+
homepage: https://github.com/clayallsopp/twittermotion
|
83
|
+
licenses: []
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.23
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: A RubyMotion Twitter Wrapper
|
106
|
+
test_files:
|
107
|
+
- spec/main_spec.rb
|