redd 0.7.10 → 0.8.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -30
  3. data/.rspec +1 -1
  4. data/.rubocop.yml +16 -3
  5. data/.travis.yml +13 -7
  6. data/Gemfile +3 -1
  7. data/LICENSE.txt +21 -0
  8. data/README.md +40 -126
  9. data/Rakefile +10 -3
  10. data/TODO.md +11 -0
  11. data/bin/console +84 -0
  12. data/bin/setup +8 -0
  13. data/lib/redd.rb +84 -46
  14. data/lib/redd/api_client.rb +109 -0
  15. data/lib/redd/auth_strategies/auth_strategy.rb +60 -0
  16. data/lib/redd/auth_strategies/installed.rb +22 -0
  17. data/lib/redd/auth_strategies/script.rb +23 -0
  18. data/lib/redd/auth_strategies/userless.rb +17 -0
  19. data/lib/redd/auth_strategies/web.rb +29 -0
  20. data/lib/redd/client.rb +88 -0
  21. data/lib/redd/error.rb +19 -142
  22. data/lib/redd/models/access.rb +20 -0
  23. data/lib/redd/models/basic_model.rb +124 -0
  24. data/lib/redd/models/comment.rb +51 -0
  25. data/lib/redd/models/front_page.rb +71 -0
  26. data/lib/redd/models/inboxable.rb +23 -0
  27. data/lib/redd/models/lazy_model.rb +63 -0
  28. data/lib/redd/models/listing.rb +26 -0
  29. data/lib/redd/models/messageable.rb +20 -0
  30. data/lib/redd/models/moderatable.rb +41 -0
  31. data/lib/redd/models/more_comments.rb +10 -0
  32. data/lib/redd/models/multireddit.rb +32 -0
  33. data/lib/redd/models/postable.rb +70 -0
  34. data/lib/redd/models/private_message.rb +29 -0
  35. data/lib/redd/models/replyable.rb +16 -0
  36. data/lib/redd/models/session.rb +86 -0
  37. data/lib/redd/models/submission.rb +40 -0
  38. data/lib/redd/models/subreddit.rb +201 -0
  39. data/lib/redd/models/user.rb +72 -0
  40. data/lib/redd/models/wiki_page.rb +24 -0
  41. data/lib/redd/utilities/error_handler.rb +35 -0
  42. data/lib/redd/utilities/rate_limiter.rb +21 -0
  43. data/lib/redd/utilities/stream.rb +63 -0
  44. data/lib/redd/utilities/unmarshaller.rb +39 -0
  45. data/lib/redd/version.rb +4 -3
  46. data/logo.png +0 -0
  47. data/redd.gemspec +26 -22
  48. metadata +73 -99
  49. data/LICENSE.md +0 -22
  50. data/RedditKit.LICENSE.md +0 -9
  51. data/lib/redd/access.rb +0 -76
  52. data/lib/redd/clients/base.rb +0 -188
  53. data/lib/redd/clients/base/account.rb +0 -20
  54. data/lib/redd/clients/base/identity.rb +0 -22
  55. data/lib/redd/clients/base/none.rb +0 -27
  56. data/lib/redd/clients/base/privatemessages.rb +0 -33
  57. data/lib/redd/clients/base/read.rb +0 -113
  58. data/lib/redd/clients/base/stream.rb +0 -81
  59. data/lib/redd/clients/base/submit.rb +0 -19
  60. data/lib/redd/clients/base/utilities.rb +0 -104
  61. data/lib/redd/clients/base/wikiread.rb +0 -33
  62. data/lib/redd/clients/installed.rb +0 -57
  63. data/lib/redd/clients/script.rb +0 -41
  64. data/lib/redd/clients/userless.rb +0 -32
  65. data/lib/redd/clients/web.rb +0 -58
  66. data/lib/redd/objects/base.rb +0 -39
  67. data/lib/redd/objects/comment.rb +0 -22
  68. data/lib/redd/objects/labeled_multi.rb +0 -13
  69. data/lib/redd/objects/listing.rb +0 -29
  70. data/lib/redd/objects/more_comments.rb +0 -11
  71. data/lib/redd/objects/private_message.rb +0 -28
  72. data/lib/redd/objects/submission.rb +0 -139
  73. data/lib/redd/objects/subreddit.rb +0 -330
  74. data/lib/redd/objects/thing.rb +0 -26
  75. data/lib/redd/objects/thing/editable.rb +0 -22
  76. data/lib/redd/objects/thing/hideable.rb +0 -18
  77. data/lib/redd/objects/thing/inboxable.rb +0 -25
  78. data/lib/redd/objects/thing/messageable.rb +0 -34
  79. data/lib/redd/objects/thing/moderatable.rb +0 -43
  80. data/lib/redd/objects/thing/refreshable.rb +0 -14
  81. data/lib/redd/objects/thing/saveable.rb +0 -21
  82. data/lib/redd/objects/thing/votable.rb +0 -33
  83. data/lib/redd/objects/user.rb +0 -52
  84. data/lib/redd/objects/wiki_page.rb +0 -15
  85. data/lib/redd/rate_limit.rb +0 -88
  86. data/lib/redd/response/parse_json.rb +0 -18
  87. data/lib/redd/response/raise_error.rb +0 -16
  88. data/spec/redd/objects/base_spec.rb +0 -1
  89. data/spec/redd/response/raise_error_spec.rb +0 -11
  90. data/spec/redd_spec.rb +0 -5
  91. data/spec/spec_helper.rb +0 -71
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e1121cb3dc661cdca2b70098ec2a384c9138b7fd
4
- data.tar.gz: bea834439ebe8bb0d24d41eadeaddfdc390090b9
3
+ metadata.gz: bc08060b2e7111adfd18a83c7d23e464f20a92dc
4
+ data.tar.gz: 79897c294f7f612e90acee7184b91a4982d54cb6
5
5
  SHA512:
6
- metadata.gz: bba0bd482a22ad71a63170be6d8eddf3b655d7438cb44912cc0d692ee0c3c73d485989ab72f1d17aa1ef836c0c05c680430b46be9f4fd45e1f1462cc38ef7169
7
- data.tar.gz: 9251eff0a74b121c7e6fe257b022edce3866346736cfbb6e6b6616a8021b6828308b534c0b67ff34301ac9057a61e98d3990c43bf578f5f6cece3301a4a3f62b
6
+ metadata.gz: 0ccfa94a4923e3748931c6ca5e5515f23c10bd23d979c1ef79e5f3f62a87c78ff66ed01f72033d95d3da3e8ca0e47cf9ebd412d758d3b751d3d935545abd787c
7
+ data.tar.gz: f2881316388b4b3b1183aebdc867184aa64750c57ac29cfb6b17532ef099f0c4de309f064f3160a3eb670ee4d70d91cee335367b9c43a34c5f70eb3254781743
data/.gitignore CHANGED
@@ -1,34 +1,9 @@
1
- *.gem
2
- *.rbc
3
- /.config
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
4
5
  /coverage/
5
- /InstalledFiles
6
+ /doc/
6
7
  /pkg/
7
8
  /spec/reports/
8
- /test/tmp/
9
- /test/version_tmp/
10
9
  /tmp/
11
-
12
- ## Specific to RubyMotion:
13
- .dat*
14
- .repl_history
15
- build/
16
-
17
- ## Documentation cache and generated files:
18
- /.yardoc/
19
- /_yardoc/
20
- /doc/
21
- /rdoc/
22
-
23
- ## Environment normalisation:
24
- /.bundle/
25
- /lib/bundler/man/
26
-
27
- # for a library or gem, you might want to ignore these files since the code is
28
- # intended to run in multiple environments; otherwise, check them in:
29
- Gemfile.lock
30
- .ruby-version
31
- .ruby-gemset
32
-
33
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
- .rvmrc
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
- --require spec_helper
2
1
  --format documentation
2
+ --require spec_helper
3
3
  --color
@@ -1,5 +1,18 @@
1
- StringLiterals:
2
- EnforcedStyle: double_quotes
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
3
 
4
- Style/SpaceInsideHashLiteralBraces:
4
+ Metrics/LineLength:
5
+ Max: 100
6
+
7
+ # Allows for raising Redd::ResponseErrors with a Response object.
8
+ Style/RaiseArgs:
5
9
  Enabled: false
10
+
11
+ # Many reddit calls demand a lot of parameters.
12
+ Metrics/ParameterLists:
13
+ CountKeywordArgs: false
14
+
15
+ # Stop rubocop from complaining about large `describe` blocks.
16
+ Metrics/BlockLength:
17
+ Exclude:
18
+ - spec/**/*_spec.rb
@@ -1,9 +1,15 @@
1
+ sudo: false
1
2
  language: ruby
2
- before_install:
3
- - gem install bundler -v 1.12
4
3
  rvm:
5
- - ruby-2.1.0
6
- - ruby-2.2.0
7
- - ruby-2
8
- - rbx-2
9
- - jruby-9.0.0.0.pre1
4
+ - ruby-head
5
+ - 2.4.0
6
+ - 2.1.0
7
+ - jruby-head
8
+ - jruby-9.1.7.0
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: ruby-head
12
+ - rvm: jruby-head
13
+
14
+ before_install: gem install bundler -v 1.13.7
15
+ cache: bundler
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in redd.gemspec
4
6
  gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Avinash Dwarapu
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,142 +1,56 @@
1
- <p align="center">
2
- <img src="https://i.imgur.com/2JfE4M1.png" alt="redd"><br>
3
- <a href="https://rubygems.org/gems/redd"><img src="http://img.shields.io/gem/v/redd.svg?style=flat-square" alt="Gem Version"></a>
4
- <a href="https://travis-ci.org/avidw/redd"><img src="http://img.shields.io/travis/avinashbot/redd.svg?style=flat-square" alt="Build Status"></a>
5
- <a href="https://rubygems.org/gems/redd"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License"></a>
6
- </p>
1
+ <div align="center">
2
+ <!-- Redd -->
3
+ <img src="logo.png" width="500"><br>
7
4
 
8
- **redd** is an API wrapper for [reddit](http://www.reddit.com/dev/api) written in ruby that focuses on being consistent and extensible. **Check out the latest documentation on [RubyDoc](http://www.rubydoc.info/github/avidw/redd/master/frames/Redd.it).**
5
+ <!-- Intro Text -->
6
+ <strong>Redd</strong> is an API wrapper
7
+ for <a href="https://www.reddit.com/dev/api">reddit</a>
8
+ that is all about being <strong>simple</strong>
9
+ and <strong>intuitive</strong>.
10
+ </div>
9
11
 
10
12
  ---
11
13
 
12
- #### Gemfile
13
14
  ```ruby
14
- gem "redd", "~> 0.7"
15
+ require 'redd'
15
16
 
16
- # Optional fast JSON parser.
17
- gem "oj", platforms: :ruby
18
- ```
19
-
20
- #### Getting Started
21
- ```ruby
22
- # Authorization (Web)
23
- w = Redd.it(:web, "CLIENT_ID", "SECRET", "REDIRECT_URI", user_agent: "TestSite v1.0.0")
24
- url = w.auth_url("random_state", ["identity", "read"], :temporary)
25
- puts "Please go to #{url} and enter the code below:"
26
- code = gets.chomp
27
- w.authorize!(code)
28
-
29
- # Authorization
30
- r = Redd.it(:script, "CLIENT_ID", "SECRET", "Unidan", "hunter2", user_agent: "TestBot v1.0.0")
31
- r.authorize!
32
-
33
- # See documentation for more grants.
34
- ```
35
-
36
- ```ruby
37
- # Access
38
- require "secure_random"
39
- require "sinatra"
40
-
41
- enable :sessions
42
-
43
- get "/auth" do
44
- state = SecureRandom.urlsafe_base64
45
- session[:state] = state
46
- redirect w.auth_url(state, %w(identity), :permanent)
47
- end
48
-
49
- get "/redirect" do
50
- halt 500, "Your state doesn't match!" unless session[:state] == params[:state]
51
- access = w.authorize!(params[:code])
52
- session[:access] = access.to_json
53
- redirect to("/name")
54
- end
17
+ session = Redd.it(
18
+ user_agent: 'Redd:RandomBot:v1.0.0 (by /u/Mustermind)',
19
+ client_id: 'PQgS0UaX9l70oQ',
20
+ secret: 'PsF_kVZrW8nSVCG5kNsIgl-AaXE',
21
+ username: 'RandomBot',
22
+ password: 'hunter2'
23
+ )
55
24
 
56
- get "/name" do
57
- if session[:access]
58
- session_access = Redd::Access.from_json(session[:access])
59
- w.with(session_access) do |client|
60
- client.refresh_access! if session_access.expired?
61
- "Your username is #{client.me.name}"
62
- end
63
- else
64
- redirect to("/auth")
25
+ session.subreddit('all').comment_stream do |comment|
26
+ if comment.body.include?('roll a dice')
27
+ comment.reply("I just rolled a dice! It's a #{rand(1..6)}!")
28
+ elsif comment.body.include?('flip a coin') || comment.body.include?('coin flip')
29
+ coin_face = (rand(0..1) == 1 ? 'heads' : 'tails')
30
+ comment.reply("I just flipped a coin! It's #{coin_face}!")
65
31
  end
66
32
  end
67
-
68
- ```
69
-
70
- ```ruby
71
- # Getting a model
72
- vargas = r.user_from_name("_vargas_")
73
- puts vargas.keys
74
- puts vargas.over_18?
75
-
76
- picturegame = r.subreddit_from_name("picturegame")
77
- puts picturegame.display_name
78
- puts picturegame.public_description
79
33
  ```
80
34
 
81
- ```ruby
82
- # Listings
83
- hot = r.get_hot("all")
84
- hot.each { |link| puts "#{link.title} by /u/#{link.author}" }
85
- ```
86
-
87
- ```ruby
88
- # Streaming
89
- def stream_all!
90
- r.stream :get_comments, "all" do |comment|
91
- reddit.refresh_access! if reddit.access.expired? # for :web
92
- comment.reply("World!") if comment.body == "Hello?"
93
- end
94
- end
95
- ```
96
-
97
- ```ruby
98
- # Escaping Errors
99
- begin
100
- stream_all!
101
- rescue Redd::Error::RateLimited => error
102
- sleep(error.time)
103
- retry
104
- rescue Redd::Error => error
105
- # 5-something errors are usually errors on reddit's end.
106
- raise error unless (500...600).include?(error.code)
107
- retry
108
- end
109
- ```
110
-
111
- #### Extras
112
- ```ruby
113
- # Extending Redd.rb
35
+ ---
114
36
 
115
- module MyGildingExtension
116
- def gild!
117
- # We're using post instead of request_object, because we don't
118
- # expect any object from the response.
119
- post("/api/v1/gold/gild/#{fullname}")
120
- end
121
- end
37
+ ### FAQ
122
38
 
123
- Redd::Objects::Comment.include(MyGildingExtension)
124
- Redd::Objects::Submission.include(MyGildingExtension)
125
- ```
39
+ #### Is that bot fully functional?
40
+ **Yes**, that's all there is to it! You don't need to handle rate-limiting, refresh access tokens
41
+ or protect against issues on reddit's end (like 5xx errors).
126
42
 
127
- ```markdown
128
- # Contributing
129
- 1. [Fork](https://github.com/avidw/redd/issues/new)
130
- 2. [Pull](https://github.com/avidw/redd/compare)
131
- 3. [Profit](https://www.reddit.com/r/requestabot)
43
+ #### How can I contact you?
44
+ [Reddit](https://www.reddit.com/message/compose/?to=Mustermind) /
45
+ [GitHub](https://github.com/avinashbot/redd/issues/new) /
46
+ [Email](mailto:avinash@dwarapu.me)
132
47
 
133
- # Request a Feature
134
- 1. [Help](https://github.com/avidw/redd/issues/new)
135
- ```
48
+ ---
136
49
 
137
- ```ruby
138
- # Copyright.rb
139
- #
140
- # Copyright (c) Avinash Dwarapu under the MIT License. See LICENSE.md for more details.
141
- # Redd::Error has been modified from RedditKit.rb. See RedditKit.LICENSE.md for its license.
142
- ```
50
+ <div align="center">
51
+ <!-- Copyright Notice -->
52
+ <em>
53
+ This project is available under the MIT License. See LICENSE.txt for more details.<br>
54
+ The Redd logo uses the FARRAY font by Coquet Adrien.
55
+ </em>
56
+ </div>
data/Rakefile CHANGED
@@ -1,5 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
3
2
 
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RuboCop::RakeTask.new do |t|
8
+ t.fail_on_error = false
9
+ end
4
10
  RSpec::Core::RakeTask.new(:spec)
5
- task default: :spec
11
+
12
+ task default: [:rubocop, :spec]
data/TODO.md ADDED
@@ -0,0 +1,11 @@
1
+ # v0.8.0 checklist
2
+
3
+ - [ ] Make v0.8.0 feature-complete with v0.7.x
4
+ - [ ] `Messageable`
5
+ - [ ] `MoreComments` and expansion
6
+ - [ ] make rubocop fail on error
7
+ - [ ] unduplicate duplicated code
8
+ - [ ] Write tests (oh boy)
9
+ - [ ] More comprehensive error checking
10
+ - [ ] A `FrontPage` object
11
+ - [ ] Add `#==` and `#to_s` methods to models
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'webrick'
5
+ require 'redd'
6
+
7
+ server = WEBrick::HTTPServer.new(
8
+ Port: 8000,
9
+ BindAddress: '0.0.0.0',
10
+ Logger: WEBrick::Log.new(File.open(File::NULL, 'w')),
11
+ AccessLog: []
12
+ )
13
+
14
+ server.mount_proc '/' do |_, res|
15
+ res.body = <<-EOS
16
+ <!doctype html>
17
+ <title>Redd Quickstart</title>
18
+ <style>
19
+ html, body { margin: 0; height: 100vh; }
20
+ .wrapper { padding-top: 30vh; text-align: center; font-family: sans-serif; }
21
+ #btn { background-color: #3D9970; margin: 5px; border-radius: 5px; padding: 10px; color: #fff; text-decoration: none; }
22
+ </style>
23
+ <div class="wrapper">
24
+ <h1>redd // quickstart</h1>
25
+ <a onclick="window.open('/authenticate', '', 'width=960,height=640')" href="#" id="btn">Start</a>
26
+ <span>a new session in your terminal?</span>
27
+ </div>
28
+ EOS
29
+ end
30
+
31
+ server.mount_proc '/authenticate' do |_, res|
32
+ res.set_redirect(
33
+ WEBrick::HTTPStatus[302],
34
+ Redd.url(
35
+ client_id: 'P4txR-D6TzF8cg',
36
+ response_type: 'code',
37
+ state: '0',
38
+ redirect_uri: 'http://localhost:8000/redirect',
39
+ 'scope': %w(identity read subscribe privatemessages wikiread submit vote edit modposts history
40
+ modflair)
41
+ )
42
+ )
43
+ end
44
+
45
+ server.mount_proc '/redirect' do |req, res|
46
+ err = req.query['error']
47
+ should_exit = err.nil? || err == 'access_denied'
48
+ res.body = <<-EOS
49
+ <!doctype html>
50
+ <title>Done!</title>
51
+ #{should_exit ? '<script>window.close();</script>' : "<p>Uh oh, there was an error: #{err}</p>"}
52
+ EOS
53
+
54
+ unless err
55
+ R = Redd.it(
56
+ user_agent: "Ruby:Redd-Quickstart:v#{Redd::VERSION} (by unknown)",
57
+ client_id: 'P4txR-D6TzF8cg',
58
+ redirect_uri: 'http://localhost:8000/redirect',
59
+ code: req.query['code']
60
+ )
61
+ server.stop
62
+ end
63
+ end
64
+
65
+ # Get the server going and shut it all down if user hits Ctrl-C
66
+ begin
67
+ puts "Listening at \e[34mhttp://localhost:8000\e[0m..."
68
+ server.start
69
+ rescue Interrupt
70
+ server.shutdown
71
+ exit
72
+ end
73
+
74
+ # Post a colourful welcome message
75
+ suggestions = [
76
+ 'R.me.link_karma',
77
+ "R.subreddit('pics').hot.first.title",
78
+ "puts R.subreddit('all').hot.map(&:title)"
79
+ ]
80
+ puts "Welcome, \e[35m/u/#{R.me.name}\e[0m! Try `\e[34m#{suggestions.sample}\e[0m`."
81
+
82
+ # Load Pry
83
+ require 'pry'
84
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -1,50 +1,88 @@
1
- require_relative "redd/version"
2
- require_relative "redd/clients/installed"
3
- require_relative "redd/clients/script"
4
- require_relative "redd/clients/userless"
5
- require_relative "redd/clients/web"
1
+ # frozen_string_literal: true
6
2
 
7
- # The main Redd module.
3
+ require 'uri'
4
+
5
+ # Redd Version
6
+ require_relative 'redd/version'
7
+ # Models
8
+ Dir[File.join(__dir__, 'redd', 'models', '*.rb')].each { |f| require f }
9
+ # Authentication Clients
10
+ Dir[File.join(__dir__, 'redd', 'auth_strategies', '*.rb')].each { |f| require f }
11
+ # Regular Client
12
+ require_relative 'redd/api_client'
13
+
14
+ # Redd is a simple and intuitive API wrapper.
8
15
  module Redd
9
- # @overload it(:installed, client_id, redirect_uri, **kwargs)
10
- # Authorize a user via an installed app.
11
- # @param [String] client_id The client ID provided by reddit.
12
- # @param [String] redirect_uri The exact uri you provided to reddit.
13
- # @param [Hash] kwargs The keyword arguments provided to the client.
14
- # @return [Clients::Installed]
15
- #
16
- # @overload it(:script, client_id, secret, username, password, **kwargs)
17
- # Authorize a user that you have full access to, i.e. a bot.
18
- # @param [String] client_id The client ID provided by reddit.
19
- # @param [String] secret The client secret provided by reddit.
20
- # @param [String] username The username.
21
- # @param [String] password The password of the user.
22
- # @param [Hash] kwargs The keyword arguments provided to the client.
23
- # @return [Clients::Script]
24
- #
25
- # @overload it(:userless, client_id, secret, **kwargs)
26
- # Connect to reddit from a web-app or a script without a specific user.
27
- # @param [String] client_id The client ID provided by reddit.
28
- # @param [String] secret The client secret provided by reddit.
29
- # @param [Hash] kwargs The keyword arguments provided to the client.
30
- # @return [Clients::Userless]
31
- #
32
- # @overload it(:web, client_id, secret, redirect_uri, **kwargs)
33
- # Authorize a user from a website.
34
- # @param [String] client_id The client ID provided by reddit.
35
- # @param [String] secret The client secret provided by reddit.
36
- # @param [String] redirect_uri The exact uri you provided to reddit.
37
- # @param [Hash] kwargs The keyword arguments provided to the client.
38
- # @return [Clients::Web]
39
- #
40
- def self.it(type, *args, **kwargs)
41
- types = {
42
- installed: Clients::Installed,
43
- script: Clients::Script,
44
- userless: Clients::Userless,
45
- web: Clients::Web
46
- }
47
-
48
- types[type].new(*args, **kwargs)
16
+ class << self
17
+ # Guesses the appropriate authentication strategy, creates an API client and starts you off with
18
+ # a {Models::Session}.
19
+ # @see https://www.reddit.com/prefs/apps
20
+ # @param opts [Hash] the options to create the object with
21
+ # @option opts [String] :user_agent your app's *unique* and *descriptive* user agent
22
+ # @option opts [String] :client_id the client id of your app
23
+ # @option opts [String] :secret the app secret (for confidential types, i.e. *not* *installed*)
24
+ # @option opts [String] :username the username of your bot (only for *script*)
25
+ # @option opts [String] :password the plaintext password of your bot (only for *script*)
26
+ # @option opts [String] :redirect_uri the provided redirect URI (only for *web* and *installed*)
27
+ # @option opts [String] :code the code given by reddit (required for *web* and *installed*)
28
+ # @return [Models::Session] a fresh {Models::Session} for you to make requests with
29
+ def it(opts = {})
30
+ api_client = script(opts) || web(opts) || installed(opts) || userless(opts)
31
+ raise "couldn't guess app type" unless api_client
32
+ Models::Session.new(api_client) { |client| client.get('/api/v1/me').body }
33
+ end
34
+
35
+ # Create a url to send to users for authorization.
36
+ # @param response_type ['code', 'token'] the type of response from reddit
37
+ # @param state [String] a randomly generated token to avoid CSRF attacks.
38
+ # @param client_id [String] the client id of the app
39
+ # @param redirect_uri [String] the URI for reddit to redirect to after authorization
40
+ # @param scope [Array<String>] an array of scopes to request
41
+ # @return [String] the generated url
42
+ def url(client_id:, redirect_uri:, response_type: 'code', state: '', scope: ['identity'])
43
+ 'https://www.reddit.com/api/v1/authorize?' + URI.encode_www_form(
44
+ client_id: client_id,
45
+ redirect_uri: redirect_uri,
46
+ state: state,
47
+ scope: scope.join(','),
48
+ response_type: response_type
49
+ )
50
+ end
51
+
52
+ private
53
+
54
+ def filter_auth(opts)
55
+ opts.select { |k| %i(client_id secret username password redirect_uri user_agent).include?(k) }
56
+ end
57
+
58
+ def filter_api(opts)
59
+ opts.select { |k| %i(user_agent).include?(k) }
60
+ end
61
+
62
+ def script(opts = {})
63
+ return unless %i(client_id secret username password).all? { |o| opts.include?(o) }
64
+ api = APIClient.new(AuthStrategies::Script.new(**filter_auth(opts)), **filter_api(opts))
65
+ api.tap(&:authenticate)
66
+ end
67
+
68
+ def web(opts = {})
69
+ return unless %i(client_id secret redirect_uri code).all? { |o| opts.include?(o) }
70
+ code = opts.delete(:code)
71
+ api = APIClient.new(AuthStrategies::Web.new(**filter_auth(opts)), **filter_api(opts))
72
+ api.tap { |c| c.authenticate(code) }
73
+ end
74
+
75
+ def installed(opts = {})
76
+ return unless %i(client_id redirect_uri code).all? { |o| opts.include?(o) }
77
+ code = opts.delete(:code)
78
+ api = APIClient.new(AuthStrategies::Installed.new(**filter_auth(opts)), **filter_api(opts))
79
+ api.tap { |c| c.authenticate(code) }
80
+ end
81
+
82
+ def userless(opts = {})
83
+ return unless %i(client_id secret).all? { |o| opts.include?(o) }
84
+ api = APIClient.new(AuthStrategies::Userless.new(**filter_auth(opts)), **filter_api(opts))
85
+ api.tap(&:authenticate)
86
+ end
49
87
  end
50
88
  end