twurl 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.travis.yml +18 -9
- data/CODE_OF_CONDUCT.md +48 -0
- data/LICENSE +21 -0
- data/{README → README.md} +69 -45
- data/lib/twurl/cli.rb +30 -15
- data/lib/twurl/oauth_client.rb +24 -5
- data/lib/twurl/request_controller.rb +8 -0
- data/lib/twurl/version.rb +1 -1
- data/twurl.gemspec +3 -5
- metadata +14 -25
- data/COPYING +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dee149b8c4ba5db925b3aa0a52182185fa432e316f72165f66b7dd088a3772a9
|
4
|
+
data.tar.gz: 612f7f0a9bbda2235f25247cb24861d851b318197355de88de0d34eff882a850
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6f1457730a541173b6a0537cf32501436e06fa3b0672cd0e81660eebaa05df7d1f4f46213ed7fd7d23896a7ffeeee0c9442bc3defdf9ae92c72b1a81232eea1
|
7
|
+
data.tar.gz: 9a06241334f788f2226b3ef1adc886cf0776e58939f8951cb27020a5dae629f75a8f296b274c5dcd61b0e6bf6bb0d1a30ca1accbe1d264060aa3f7758d890613
|
@@ -0,0 +1,13 @@
|
|
1
|
+
One line summary of the issue here.
|
2
|
+
|
3
|
+
### Expected behavior
|
4
|
+
|
5
|
+
As concisely as possible, describe the expected behavior.
|
6
|
+
|
7
|
+
### Actual behavior
|
8
|
+
|
9
|
+
As concisely as possible, describe the observed behavior.
|
10
|
+
|
11
|
+
### Steps to reproduce the behavior
|
12
|
+
|
13
|
+
Please list all relevant steps to reproduce the observed behavior.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Problem
|
2
|
+
|
3
|
+
Explain the context and why you're making that change. What is the
|
4
|
+
problem you're trying to solve? In some cases there is not a problem
|
5
|
+
and this can be thought of being the motivation for your change.
|
6
|
+
|
7
|
+
Solution
|
8
|
+
|
9
|
+
Describe the modifications you've done.
|
10
|
+
|
11
|
+
Result
|
12
|
+
|
13
|
+
What will change as a result of your pull request? Note that sometimes
|
14
|
+
this section is unnecessary because it is self-explanatory based on
|
15
|
+
the solution.
|
data/.travis.yml
CHANGED
@@ -1,14 +1,23 @@
|
|
1
|
-
|
1
|
+
dist: xenial
|
2
2
|
language: ruby
|
3
|
-
|
4
|
-
|
5
|
-
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
|
4
|
+
before_install:
|
5
|
+
- bundle config without 'development'
|
6
|
+
|
7
|
+
branches:
|
8
|
+
only:
|
9
|
+
- master
|
10
|
+
|
9
11
|
matrix:
|
12
|
+
fast_finish: true
|
10
13
|
allow_failures:
|
11
14
|
- rvm: jruby-head
|
12
15
|
- rvm: ruby-head
|
13
|
-
|
14
|
-
|
16
|
+
- rvm: rbx-2
|
17
|
+
include:
|
18
|
+
- rvm: 2.6.5
|
19
|
+
- rvm: 2.5.7
|
20
|
+
- rvm: 2.4.9
|
21
|
+
- rvm: jruby-head
|
22
|
+
- rvm: ruby-head
|
23
|
+
- rvm: rbx-2
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Code of Conduct v2.0
|
2
|
+
|
3
|
+
This code of conduct outlines our expectations for participants within the [@TwitterOSS](https://twitter.com/twitteross) community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community.
|
4
|
+
|
5
|
+
Our open source community strives to:
|
6
|
+
|
7
|
+
* **Be friendly and patient.**
|
8
|
+
* **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
|
9
|
+
* **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
|
10
|
+
* **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one.
|
11
|
+
* **Be careful in the words that you choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
|
12
|
+
* Violent threats or language directed against another person.
|
13
|
+
* Discriminatory jokes and language.
|
14
|
+
* Posting sexually explicit or violent material.
|
15
|
+
* Posting (or threatening to post) other people's personally identifying information ("doxing").
|
16
|
+
* Personal insults, especially those using racist or sexist terms.
|
17
|
+
* Unwelcome sexual attention.
|
18
|
+
* Advocating for, or encouraging, any of the above behavior.
|
19
|
+
* Repeated harassment of others. In general, if someone asks you to stop, then stop.
|
20
|
+
* **When we disagree, try to understand why**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
|
21
|
+
|
22
|
+
This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter.
|
23
|
+
|
24
|
+
### Diversity Statement
|
25
|
+
|
26
|
+
We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
|
27
|
+
|
28
|
+
Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected
|
29
|
+
characteristics above, including participants with disabilities.
|
30
|
+
|
31
|
+
### Reporting Issues
|
32
|
+
|
33
|
+
If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via [opensource+codeofconduct@twitter.com](mailto:opensource+codeofconduct@twitter.com). All reports will be handled with discretion. In your report please include:
|
34
|
+
|
35
|
+
- Your contact information.
|
36
|
+
- Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please
|
37
|
+
include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
|
38
|
+
- Any additional information that may be helpful.
|
39
|
+
|
40
|
+
After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse.
|
41
|
+
|
42
|
+
Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning.
|
43
|
+
|
44
|
+
## Thanks
|
45
|
+
|
46
|
+
This code of conduct is based on the [Open Code of Conduct](https://github.com/todogroup/opencodeofconduct) from the [TODOGroup](http://todogroup.org).
|
47
|
+
|
48
|
+
We are thankful for their work and all the communities who have paved the way with code of conducts.
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Marcel Molina <marcel@twitter.com>, 2019 Twitter, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/{README → README.md}
RENAMED
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
+-------+
|
1
|
+
Twurl
|
2
|
+
=====
|
4
3
|
|
5
4
|
Twurl is like curl, but tailored specifically for the Twitter API.
|
6
5
|
It knows how to grant an access token to a client application for
|
@@ -11,109 +10,134 @@ as defining aliases for common requests, as well as support for
|
|
11
10
|
multiple access tokens to easily switch between different client
|
12
11
|
applications and Twitter accounts.
|
13
12
|
|
14
|
-
+-----------------+
|
15
|
-
| Getting Started |
|
16
|
-
+-----------------+
|
17
13
|
|
18
|
-
|
19
|
-
|
14
|
+
Installing Twurl
|
15
|
+
----------------
|
20
16
|
|
21
|
-
|
17
|
+
Twurl can be installed using ruby gems:
|
18
|
+
|
19
|
+
```
|
20
|
+
gem install twurl
|
21
|
+
```
|
22
|
+
|
23
|
+
|
24
|
+
Getting Started
|
25
|
+
---------------
|
26
|
+
|
27
|
+
If you haven't already, the first thing to do is apply for a developer account to access Twitter APIs:
|
28
|
+
|
29
|
+
```
|
30
|
+
https://developer.twitter.com/en/apply-for-access
|
31
|
+
```
|
32
|
+
|
33
|
+
After you have that access you can create a Twitter app and generate a consumer key and secret.
|
34
|
+
|
22
35
|
|
23
36
|
When you have your consumer key and its secret you authorize
|
24
37
|
your Twitter account to make API requests with your consumer key
|
25
38
|
and secret.
|
26
39
|
|
27
|
-
|
28
|
-
|
40
|
+
```
|
41
|
+
twurl authorize --consumer-key key \
|
42
|
+
--consumer-secret secret
|
43
|
+
```
|
29
44
|
|
30
45
|
This will return an URL that you should open up in your browser.
|
31
46
|
Authenticate to Twitter, and then enter the returned PIN back into
|
32
47
|
the terminal. Assuming all that works well, you will be authorized
|
33
48
|
to make requests with the API. Twurl will tell you as much.
|
34
49
|
|
35
|
-
If your consumer application has xAuth enabled, then you can use
|
36
|
-
a variant of the above
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
--consumer-secret secret
|
41
|
-
|
42
|
-
And, again assuming your username, password, key and secret is
|
43
|
-
correct, will authorize you in one step.
|
44
|
-
|
45
|
-
+-----------------+
|
46
|
-
| Making Requests |
|
47
|
-
+-----------------+
|
51
|
+
Making Requests
|
52
|
+
---------------
|
48
53
|
|
49
54
|
The simplest request just requires that you specify the path you
|
50
55
|
want to request.
|
51
56
|
|
52
|
-
|
57
|
+
```
|
58
|
+
twurl /1.1/statuses/home_timeline.json
|
59
|
+
```
|
53
60
|
|
54
61
|
Similar to curl, a GET request is performed by default.
|
55
62
|
|
56
63
|
You can implicitly perform a POST request by passing the -d option,
|
57
64
|
which specifies POST parameters.
|
58
65
|
|
59
|
-
|
66
|
+
```
|
67
|
+
twurl -d 'status=Testing twurl' /1.1/statuses/update.json
|
68
|
+
```
|
60
69
|
|
61
70
|
You can explicitly specify what request method to perform with
|
62
71
|
the -X (or --request-method) option.
|
63
72
|
|
64
|
-
|
73
|
+
```
|
74
|
+
twurl -X POST /1.1/statuses/destroy/1234567890.json
|
75
|
+
```
|
76
|
+
|
65
77
|
|
66
|
-
|
67
|
-
|
68
|
-
+------------------+
|
78
|
+
Creating aliases
|
79
|
+
----------------
|
69
80
|
|
70
|
-
|
81
|
+
```
|
82
|
+
twurl alias h /1.1/statuses/home_timeline.json
|
83
|
+
```
|
71
84
|
|
72
85
|
You can then use "h" in place of the full path.
|
73
86
|
|
74
|
-
|
87
|
+
```
|
88
|
+
twurl h
|
89
|
+
```
|
75
90
|
|
76
91
|
Paths that require additional options such as request parameters for example can
|
77
92
|
be used with aliases the same as with full explicit paths, just as you might
|
78
93
|
expect.
|
79
94
|
|
80
|
-
|
81
|
-
|
95
|
+
```
|
96
|
+
twurl alias tweet /1.1/statuses/update.json
|
97
|
+
twurl tweet -d "status=Aliases in twurl are convenient"
|
98
|
+
```
|
82
99
|
|
83
|
-
|
84
|
-
|
85
|
-
|
100
|
+
|
101
|
+
Changing your default profile
|
102
|
+
-----------------------------
|
86
103
|
|
87
104
|
The first time you authorize a client application to make requests on behalf of your account, twurl stores your access token information in its .twurlrc file. Subsequent requests will use this profile as the default profile. You can use the 'accounts' subcommand to see what client applications have been authorized for what user names:
|
88
105
|
|
89
|
-
|
106
|
+
```
|
107
|
+
twurl accounts
|
90
108
|
noradio
|
91
109
|
HQsAGcBm5MQT4n6j7qVJw
|
92
110
|
hhC7Koy2zRsTZvQh1hVlSA (default)
|
93
111
|
testiverse
|
94
112
|
guT9RsJbNQgVe6AwoY9BA
|
113
|
+
```
|
95
114
|
|
96
115
|
Notice that one of those consumer keys is marked as the default. To change the default use the 'set' subcommand, passing then either just the username, if it's unambiguous, or the username and consumer key pair if it isn't unambiguous:
|
97
116
|
|
98
|
-
|
99
|
-
|
117
|
+
```
|
118
|
+
twurl set default testiverse
|
119
|
+
twurl accounts
|
100
120
|
noradio
|
101
121
|
HQsAGcBm5MQT4n6j7qVJw
|
102
122
|
hhC7Koy2zRsTZvQh1hVlSA
|
103
123
|
testiverse
|
104
124
|
guT9RsJbNQgVe6AwoY9BA (default)
|
125
|
+
```
|
105
126
|
|
106
|
-
|
107
|
-
|
127
|
+
```
|
128
|
+
twurl set default noradio HQsAGcBm5MQT4n6j7qVJw
|
129
|
+
twurl accounts
|
108
130
|
noradio
|
109
131
|
HQsAGcBm5MQT4n6j7qVJw (default)
|
110
132
|
hhC7Koy2zRsTZvQh1hVlSA
|
111
133
|
testiverse
|
112
134
|
guT9RsJbNQgVe6AwoY9BA
|
135
|
+
```
|
113
136
|
|
114
|
-
|
115
|
-
|
116
|
-
+--------------+
|
137
|
+
Contributors
|
138
|
+
------------
|
117
139
|
|
118
|
-
Marcel Molina <marcel@twitter.com> / @noradio
|
140
|
+
Marcel Molina <marcel@twitter.com> / @noradio
|
119
141
|
Erik Michaels-Ober / @sferik
|
142
|
+
|
143
|
+
and there are many [more](https://github.com/twitter/twurl/graphs/contributors)!
|
data/lib/twurl/cli.rb
CHANGED
@@ -4,7 +4,7 @@ module Twurl
|
|
4
4
|
DEFAULT_COMMAND = 'request'
|
5
5
|
PATH_PATTERN = /^\/\w+/
|
6
6
|
PROTOCOL_PATTERN = /^\w+:\/\//
|
7
|
-
README = File.dirname(__FILE__) + '/../../README'
|
7
|
+
README = File.dirname(__FILE__) + '/../../README.md'
|
8
8
|
@output ||= STDOUT
|
9
9
|
class NoPathFound < Exception
|
10
10
|
end
|
@@ -41,9 +41,8 @@ module Twurl
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def parse_options(args)
|
44
|
-
arguments = args.dup
|
45
|
-
|
46
44
|
Twurl.options = Options.new
|
45
|
+
Twurl.options.args = args.dup
|
47
46
|
Twurl.options.trace = false
|
48
47
|
Twurl.options.data = {}
|
49
48
|
Twurl.options.headers = {}
|
@@ -88,19 +87,21 @@ Supported Commands: #{SUPPORTED_COMMANDS.sort.join(', ')}
|
|
88
87
|
file
|
89
88
|
filefield
|
90
89
|
base64
|
90
|
+
timeout
|
91
|
+
connection_timeout
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
94
95
|
arguments = option_parser.parse!(args)
|
95
96
|
Twurl.options.command = extract_command!(arguments)
|
96
97
|
Twurl.options.path = extract_path!(arguments)
|
97
|
-
|
98
|
-
|
98
|
+
Twurl.options.subcommands = arguments
|
99
|
+
|
100
|
+
if Twurl.options.command == DEFAULT_COMMAND and Twurl.options.path.nil? and Twurl.options.args.empty?
|
99
101
|
CLI.puts option_parser
|
100
102
|
raise NoPathFound, "No path found"
|
101
103
|
end
|
102
104
|
|
103
|
-
Twurl.options.subcommands = arguments
|
104
105
|
Twurl.options
|
105
106
|
end
|
106
107
|
|
@@ -159,11 +160,9 @@ Supported Commands: #{SUPPORTED_COMMANDS.sort.join(', ')}
|
|
159
160
|
end
|
160
161
|
|
161
162
|
def escape_params(params)
|
162
|
-
|
163
|
-
key
|
164
|
-
|
165
|
-
end
|
166
|
-
split_params.join("&")
|
163
|
+
CGI::parse(params).map do |key, value|
|
164
|
+
"#{CGI.escape key}=#{CGI.escape value.first}"
|
165
|
+
end.join("&")
|
167
166
|
end
|
168
167
|
end
|
169
168
|
|
@@ -205,7 +204,7 @@ Supported Commands: #{SUPPORTED_COMMANDS.sort.join(', ')}
|
|
205
204
|
end
|
206
205
|
|
207
206
|
def token_secret
|
208
|
-
on('-S', '--token-secret', "Your token secret") do |secret|
|
207
|
+
on('-S', '--token-secret [secret]', "Your token secret") do |secret|
|
209
208
|
options.token_secret = secret
|
210
209
|
end
|
211
210
|
end
|
@@ -230,9 +229,13 @@ Supported Commands: #{SUPPORTED_COMMANDS.sort.join(', ')}
|
|
230
229
|
|
231
230
|
def data
|
232
231
|
on('-d', '--data [data]', 'Sends the specified data in a POST request to the HTTP server.') do |data|
|
233
|
-
|
234
|
-
|
235
|
-
|
232
|
+
if options.args.count { |item| /content-type: (.*)/i.match(item) } > 0
|
233
|
+
options.data[data] = nil
|
234
|
+
else
|
235
|
+
data.split('&').each do |pair|
|
236
|
+
key, value = pair.split('=', 2)
|
237
|
+
options.data[key] = value
|
238
|
+
end
|
236
239
|
end
|
237
240
|
end
|
238
241
|
end
|
@@ -323,6 +326,18 @@ Supported Commands: #{SUPPORTED_COMMANDS.sort.join(', ')}
|
|
323
326
|
options.upload['base64'] = base64
|
324
327
|
end
|
325
328
|
end
|
329
|
+
|
330
|
+
def timeout
|
331
|
+
on('--timeout [sec]', Integer, 'Number of seconds to wait for the request to be read (default: 60)') do |timeout|
|
332
|
+
options.timeout = timeout
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def connection_timeout
|
337
|
+
on('--connection-timeout [sec]', Integer, 'Number of seconds to wait for the connection to open (default: 60)') do |connection_timeout|
|
338
|
+
options.connection_timeout = connection_timeout
|
339
|
+
end
|
340
|
+
end
|
326
341
|
end
|
327
342
|
end
|
328
343
|
|
data/lib/twurl/oauth_client.rb
CHANGED
@@ -11,7 +11,9 @@ module Twurl
|
|
11
11
|
def load_from_options(options)
|
12
12
|
if rcfile.has_oauth_profile_for_username_with_consumer_key?(options.username, options.consumer_key)
|
13
13
|
load_client_for_username_and_consumer_key(options.username, options.consumer_key)
|
14
|
-
elsif options.username
|
14
|
+
elsif options.username
|
15
|
+
load_client_for_username(options.username)
|
16
|
+
elsif options.command == 'authorize'
|
15
17
|
load_new_client_from_options(options)
|
16
18
|
else
|
17
19
|
load_default_client
|
@@ -97,10 +99,10 @@ module Twurl
|
|
97
99
|
multipart_body << "\r\n"
|
98
100
|
|
99
101
|
if options.upload['base64']
|
100
|
-
enc = Base64.encode64(File.
|
102
|
+
enc = Base64.encode64(File.binread(filename))
|
101
103
|
multipart_body << enc
|
102
104
|
else
|
103
|
-
multipart_body << File.
|
105
|
+
multipart_body << File.binread(filename)
|
104
106
|
end
|
105
107
|
}
|
106
108
|
|
@@ -111,13 +113,26 @@ module Twurl
|
|
111
113
|
elsif request.content_type && options.data
|
112
114
|
request.body = options.data.keys.first
|
113
115
|
elsif options.data
|
114
|
-
request.
|
116
|
+
request.content_type = "application/x-www-form-urlencoded"
|
117
|
+
if options.data.length == 1 && options.data.values.first == nil
|
118
|
+
request.body = options.data.keys.first
|
119
|
+
else
|
120
|
+
request.body = options.data.map do |key, value|
|
121
|
+
"#{key}=#{CGI.escape value}"
|
122
|
+
end.join("&")
|
123
|
+
end
|
115
124
|
end
|
116
125
|
|
117
126
|
request.oauth!(consumer.http, consumer, access_token)
|
127
|
+
request['user-agent'] = user_agent
|
118
128
|
consumer.http.request(request, &block)
|
119
129
|
end
|
120
130
|
|
131
|
+
def user_agent
|
132
|
+
"twurl version: #{Version} " \
|
133
|
+
"platform: #{RUBY_ENGINE} #{RUBY_VERSION} (#{RUBY_PLATFORM})"
|
134
|
+
end
|
135
|
+
|
121
136
|
def exchange_credentials_for_access_token
|
122
137
|
response = begin
|
123
138
|
consumer.token_request(:post, consumer.access_token_path, nil, {}, client_auth_parameters)
|
@@ -135,7 +150,7 @@ module Twurl
|
|
135
150
|
def perform_pin_authorize_workflow
|
136
151
|
@request_token = consumer.get_request_token
|
137
152
|
CLI.puts("Go to #{generate_authorize_url} and paste in the supplied PIN")
|
138
|
-
pin = gets
|
153
|
+
pin = STDIN.gets
|
139
154
|
access_token = @request_token.get_access_token(:oauth_verifier => pin.chomp)
|
140
155
|
{:oauth_token => access_token.token, :oauth_token_secret => access_token.secret}
|
141
156
|
end
|
@@ -191,6 +206,10 @@ module Twurl
|
|
191
206
|
|
192
207
|
def configure_http!
|
193
208
|
consumer.http.set_debug_output(Twurl.options.debug_output_io) if Twurl.options.trace
|
209
|
+
consumer.http.read_timeout = consumer.http.open_timeout = Twurl.options.timeout || 60
|
210
|
+
consumer.http.open_timeout = Twurl.options.connection_timeout if Twurl.options.connection_timeout
|
211
|
+
# Only override if Net::HTTP support max_retries (since Ruby >= 2.5)
|
212
|
+
consumer.http.max_retries = 0 if consumer.http.respond_to?(:max_retries=)
|
194
213
|
if Twurl.options.ssl?
|
195
214
|
consumer.http.use_ssl = true
|
196
215
|
consumer.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Twurl
|
2
2
|
class RequestController < AbstractCommandController
|
3
3
|
NO_URI_MESSAGE = "No URI specified"
|
4
|
+
READ_TIMEOUT_MESSAGE = 'A timeout occurred (Net::ReadTimeout). ' \
|
5
|
+
'Please try again or increase the value using --timeout option.'
|
6
|
+
OPEN_TIMEOUT_MESSAGE = 'A timeout occurred (Net::OpenTimeout). ' \
|
7
|
+
'Please try again or increase the value using --connection-timeout option.'
|
4
8
|
def dispatch
|
5
9
|
if client.needs_to_authorize?
|
6
10
|
raise Exception, "You need to authorize first."
|
@@ -15,6 +19,10 @@ module Twurl
|
|
15
19
|
}
|
16
20
|
rescue URI::InvalidURIError
|
17
21
|
CLI.puts NO_URI_MESSAGE
|
22
|
+
rescue Net::ReadTimeout
|
23
|
+
CLI.puts READ_TIMEOUT_MESSAGE
|
24
|
+
rescue Net::OpenTimeout
|
25
|
+
CLI.puts OPEN_TIMEOUT_MESSAGE
|
18
26
|
end
|
19
27
|
end
|
20
28
|
end
|
data/lib/twurl/version.rb
CHANGED
@@ -2,7 +2,7 @@ module Twurl
|
|
2
2
|
class Version
|
3
3
|
MAJOR = 0 unless defined? Twurl::Version::MAJOR
|
4
4
|
MINOR = 9 unless defined? Twurl::Version::MINOR
|
5
|
-
PATCH =
|
5
|
+
PATCH = 4 unless defined? Twurl::Version::PATCH
|
6
6
|
PRE = nil unless defined? Twurl::Version::PRE # Time.now.to_i.to_s
|
7
7
|
|
8
8
|
class << self
|
data/twurl.gemspec
CHANGED
@@ -5,20 +5,18 @@ require 'twurl/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.add_dependency 'oauth', '~> 0.4'
|
8
|
-
spec.add_development_dependency 'bundler', '~> 1.0'
|
9
8
|
spec.authors = ["Marcel Molina", "Erik Michaels-Ober"]
|
10
9
|
spec.description = %q{Curl for the Twitter API}
|
11
10
|
spec.email = ['marcel@twitter.com']
|
12
11
|
spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
-
spec.extra_rdoc_files = %w(
|
12
|
+
spec.extra_rdoc_files = %w(CODE_OF_CONDUCT.md INSTALL LICENSE README.md)
|
14
13
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.start_with?('test/') }
|
15
14
|
spec.homepage = 'http://github.com/twitter/twurl'
|
16
15
|
spec.licenses = ['MIT']
|
17
16
|
spec.name = 'twurl'
|
18
|
-
spec.rdoc_options = ['--title', 'twurl -- OAuth-enabled curl for the Twitter API', '--main', 'README', '--line-numbers', '--inline-source']
|
17
|
+
spec.rdoc_options = ['--title', 'twurl -- OAuth-enabled curl for the Twitter API', '--main', 'README.md', '--line-numbers', '--inline-source']
|
19
18
|
spec.require_paths = ['lib']
|
20
|
-
spec.required_ruby_version = '>=
|
21
|
-
spec.required_rubygems_version = '>= 1.3.5'
|
19
|
+
spec.required_ruby_version = '>= 2.4.0'
|
22
20
|
spec.rubyforge_project = 'twurl'
|
23
21
|
spec.summary = spec.description
|
24
22
|
spec.version = Twurl::Version
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twurl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcel Molina
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-12-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oauth
|
@@ -25,20 +25,6 @@ dependencies:
|
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0.4'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: bundler
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - "~>"
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '1.0'
|
35
|
-
type: :development
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - "~>"
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '1.0'
|
42
28
|
description: Curl for the Twitter API
|
43
29
|
email:
|
44
30
|
- marcel@twitter.com
|
@@ -46,16 +32,20 @@ executables:
|
|
46
32
|
- twurl
|
47
33
|
extensions: []
|
48
34
|
extra_rdoc_files:
|
49
|
-
-
|
35
|
+
- CODE_OF_CONDUCT.md
|
50
36
|
- INSTALL
|
51
|
-
-
|
37
|
+
- LICENSE
|
38
|
+
- README.md
|
52
39
|
files:
|
40
|
+
- ".github/ISSUE_TEMPLATE.md"
|
41
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
53
42
|
- ".gitignore"
|
54
43
|
- ".travis.yml"
|
55
|
-
-
|
44
|
+
- CODE_OF_CONDUCT.md
|
56
45
|
- Gemfile
|
57
46
|
- INSTALL
|
58
|
-
-
|
47
|
+
- LICENSE
|
48
|
+
- README.md
|
59
49
|
- Rakefile
|
60
50
|
- bin/twurl
|
61
51
|
- lib/twurl.rb
|
@@ -79,7 +69,7 @@ rdoc_options:
|
|
79
69
|
- "--title"
|
80
70
|
- twurl -- OAuth-enabled curl for the Twitter API
|
81
71
|
- "--main"
|
82
|
-
- README
|
72
|
+
- README.md
|
83
73
|
- "--line-numbers"
|
84
74
|
- "--inline-source"
|
85
75
|
require_paths:
|
@@ -88,15 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
78
|
requirements:
|
89
79
|
- - ">="
|
90
80
|
- !ruby/object:Gem::Version
|
91
|
-
version:
|
81
|
+
version: 2.4.0
|
92
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
83
|
requirements:
|
94
84
|
- - ">="
|
95
85
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
86
|
+
version: '0'
|
97
87
|
requirements: []
|
98
|
-
|
99
|
-
rubygems_version: 2.4.8
|
88
|
+
rubygems_version: 3.0.6
|
100
89
|
signing_key:
|
101
90
|
specification_version: 4
|
102
91
|
summary: Curl for the Twitter API
|
data/COPYING
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# Copyright (c) 2009 Marcel Molina <marcel@twitter.com>, Twitter, Inc.
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
-
# this software and associated documentation files (the "Software"), to deal in the
|
5
|
-
# Software without restriction, including without limitation the rights to use,
|
6
|
-
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
7
|
-
# Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
-
# subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in all
|
11
|
-
# copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
-
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
17
|
-
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|