ruqqus 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd42579f445107afb73ab5bddc39fda6140c1fed069b05f65dd9cf57553ae3d8
4
- data.tar.gz: 7e4e2e8ef4de56a77004e94454ef47d0312d80de869efba80061214ae29bc729
3
+ metadata.gz: a01559e849bc401630ad22455035ae0d00891f34e294eb00ea9780b82c932620
4
+ data.tar.gz: 56f99a8360fd71eb431dcf3d263f106412766f2afd51cdcda237aa643b9bb76d
5
5
  SHA512:
6
- metadata.gz: a5261490b9979f2c5817ad9ab8708862cae3e98870631ec6e31cdda4c068465a773bd08a54a5a3d04a3e7dc7bbcd8b655b03d9ec59ee9aa45d7cee84621b7c79
7
- data.tar.gz: e48634320aafc078099254ae5b74e4222b1ea2b8b043c71bd76168b53607c56e58ca43b196da7ef0ead733439abc7c3f3006add27392f700c3a165dbcd3f37ab
6
+ metadata.gz: 1417f32ba0e67970c1305c0f2cf48873fd6c4a6ffe5c6df98cb799f1459bf0ec364762a78f3eff4fb756b367e13650eeea7b8a62b516623e476b4d8488b7a167
7
+ data.tar.gz: 485fadd5ed20a3d6b1290ce709c9d5881f0f4a5ec890196fa16deff6b500ecfeb0f1f030a4dcc5eaeff853c9d2ac22a6180d080ed3cf583bf7679d2b9a10aa7c
data/.gitignore CHANGED
@@ -1,8 +1,167 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
1
+
2
+ # Created by https://www.toptal.com/developers/gitignore/api/ruby,rubymine+all,visualstudiocode
3
+ # Edit at https://www.toptal.com/developers/gitignore?templates=ruby,rubymine+all,visualstudiocode
4
+
5
+ ### Ruby ###
6
+ *.gem
7
+ *.rbc
8
+ /.config
4
9
  /coverage/
5
- /doc/
10
+ /InstalledFiles
6
11
  /pkg/
7
12
  /spec/reports/
13
+ /spec/examples.txt
14
+ /test/tmp/
15
+ /test/version_tmp/
8
16
  /tmp/
17
+
18
+ # Used by dotenv library to load environment variables.
19
+ # .env
20
+
21
+ # Ignore Byebug command history file.
22
+ .byebug_history
23
+
24
+ ## Specific to RubyMotion:
25
+ .dat*
26
+ .repl_history
27
+ build/
28
+ *.bridgesupport
29
+ build-iPhoneOS/
30
+ build-iPhoneSimulator/
31
+
32
+ ## Specific to RubyMotion (use of CocoaPods):
33
+ #
34
+ # We recommend against adding the Pods directory to your .gitignore. However
35
+ # you should judge for yourself, the pros and cons are mentioned at:
36
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
37
+ # vendor/Pods/
38
+
39
+ ## Documentation cache and generated files:
40
+ /.yardoc/
41
+ /_yardoc/
42
+ /doc/
43
+ /rdoc/
44
+
45
+ ## Environment normalization:
46
+ /.bundle/
47
+ /vendor/bundle
48
+ /lib/bundler/man/
49
+
50
+ # for a library or gem, you might want to ignore these files since the code is
51
+ # intended to run in multiple environments; otherwise, check them in:
52
+ Gemfile.lock
53
+ # .ruby-version
54
+ # .ruby-gemset
55
+
56
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
57
+ .rvmrc
58
+
59
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
60
+ # .rubocop-https?--*
61
+
62
+ ### Ruby Patch ###
63
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
64
+ # .rubocop-https?--*
65
+
66
+ ### RubyMine+all ###
67
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
68
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
69
+
70
+ # User-specific stuff
71
+ .idea/**/workspace.xml
72
+ .idea/**/tasks.xml
73
+ .idea/**/usage.statistics.xml
74
+ .idea/**/dictionaries
75
+ .idea/**/shelf
76
+
77
+ # Generated files
78
+ .idea/**/contentModel.xml
79
+
80
+ # Sensitive or high-churn files
81
+ .idea/**/dataSources/
82
+ .idea/**/dataSources.ids
83
+ .idea/**/dataSources.local.xml
84
+ .idea/**/sqlDataSources.xml
85
+ .idea/**/dynamic.xml
86
+ .idea/**/uiDesigner.xml
87
+ .idea/**/dbnavigator.xml
88
+
89
+ # Gradle
90
+ .idea/**/gradle.xml
91
+ .idea/**/libraries
92
+
93
+ # Gradle and Maven with auto-import
94
+ # When using Gradle or Maven with auto-import, you should exclude module files,
95
+ # since they will be recreated, and may cause churn. Uncomment if using
96
+ # auto-import.
97
+ # .idea/artifacts
98
+ # .idea/compiler.xml
99
+ # .idea/jarRepositories.xml
100
+ # .idea/modules.xml
101
+ # .idea/*.iml
102
+ # .idea/modules
103
+ # *.iml
104
+ # *.ipr
105
+
106
+ # CMake
107
+ cmake-build-*/
108
+
109
+ # Mongo Explorer plugin
110
+ .idea/**/mongoSettings.xml
111
+
112
+ # File-based project format
113
+ *.iws
114
+
115
+ # IntelliJ
116
+ out/
117
+
118
+ # mpeltonen/sbt-idea plugin
119
+ .idea_modules/
120
+
121
+ # JIRA plugin
122
+ atlassian-ide-plugin.xml
123
+
124
+ # Cursive Clojure plugin
125
+ .idea/replstate.xml
126
+
127
+ # Crashlytics plugin (for Android Studio and IntelliJ)
128
+ com_crashlytics_export_strings.xml
129
+ crashlytics.properties
130
+ crashlytics-build.properties
131
+ fabric.properties
132
+
133
+ # Editor-based Rest Client
134
+ .idea/httpRequests
135
+
136
+ # Android studio 3.1+ serialized cache file
137
+ .idea/caches/build_file_checksums.ser
138
+
139
+ ### RubyMine+all Patch ###
140
+ # Ignores the whole .idea folder and all .iml files
141
+ # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
142
+
143
+ .idea/
144
+
145
+ # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
146
+
147
+ *.iml
148
+ modules.xml
149
+ .idea/misc.xml
150
+ *.ipr
151
+
152
+ # Sonarlint plugin
153
+ .idea/sonarlint
154
+
155
+ ### VisualStudioCode ###
156
+ .vscode/*
157
+ !.vscode/settings.json
158
+ !.vscode/tasks.json
159
+ !.vscode/launch.json
160
+ !.vscode/extensions.json
161
+ *.code-workspace
162
+
163
+ ### VisualStudioCode Patch ###
164
+ # Ignore all local history of files
165
+ .history
166
+
167
+ # End of https://www.toptal.com/developers/gitignore/api/ruby,rubymine+all,visualstudiocode
@@ -0,0 +1,6 @@
1
+ --readme README.md
2
+ --title 'Ruqqus'
3
+ --charset utf-8
4
+ --markup markdown
5
+ --protected
6
+ lib/**/*.rb
@@ -2,7 +2,6 @@
2
2
 
3
3
  Documentation for library API changes.
4
4
 
5
- ## Version 0.1
5
+ ## Version 1.0
6
6
 
7
- *
8
- *
7
+ * Initial release, 100% coverage of existing Ruqqus API
data/Gemfile CHANGED
@@ -1,7 +1,4 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in ruqqus.gemspec
4
4
  gemspec
5
-
6
- gem "rake", "~> 12.0"
7
- gem "minitest", "~> 5.0"
data/README.md CHANGED
@@ -1,8 +1,19 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/ruqqus/ruqqus/master/ruqqus/assets/images/logo/ruqqus_text_logo.png" width="250"/>
3
+ </p>
4
+
5
+ <hr>
6
+
1
7
  # Ruqqus
2
8
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ruqqus`. To experiment with that code, run `bin/console` for an interactive prompt.
9
+ A Ruby API implementation for [Ruqqus](https://ruqqus.com/), an [open-source](https://github.com/ruqqus/ruqqus) platform for online communities, free of censorship and moderator abuse by design.
10
+
11
+ While platform is still in Beta at this time and the public API for it is still quite limited, this gem will be actively updated as it continues to grow and is developed.
4
12
 
5
- TODO: Delete this and the text above, and describe your gem
13
+ [![Build Status](https://travis-ci.org/ForeverZer0/ruqqus.svg?branch=master)](https://travis-ci.org/ForeverZer0/ruqqus)
14
+ [![Gem Version](https://badge.fury.io/rb/ruqqus.svg)](https://badge.fury.io/rb/ruqqus)
15
+ [![Inline docs](http://inch-ci.org/github/ForeverZer0/ruqqus.svg?branch=master)](http://inch-ci.org/github/ForeverZer0/ruqqus)
16
+ [![Maintainability](https://api.codeclimate.com/v1/badges/c39f44a706302e4cd340/maintainability)](https://codeclimate.com/github/ForeverZer0/ruqqus/maintainability)
6
17
 
7
18
  ## Installation
8
19
 
@@ -22,18 +33,103 @@ Or install it yourself as:
22
33
 
23
34
  ## Usage
24
35
 
25
- TODO: Write usage instructions here
36
+ At this time, there are only four publicly exposed functions to utilize for acquiring information on the following items:
26
37
 
27
- ## Development
38
+ * Users
39
+ * Guilds
40
+ * Posts
41
+ * Comments
28
42
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
43
+ The full documentation can be found [here](https://www.rubydoc.info/gems/ruqqus), but the API is rather intuitive. Here is some basic examples to give a taste of its basic usage.
30
44
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
45
+ ### Users
32
46
 
33
- ## Contributing
47
+ Obtain information about users.
48
+
49
+ ```ruby
50
+ user = Ruqqus.user('foreverzer0')
51
+
52
+ # Get user's total rep (as well as separate for comments/posts)
53
+ user.total_rep
54
+ #=> 22234
55
+
56
+ # Enumerate earned badges
57
+ user.badges.map(&:to_s)
58
+ #=> ["Joined Ruqqus during open beta", "Verified Email", "Recruited 10 friends to join Ruqqus"]
59
+
60
+ # Retrieve a Time object for when user created account
61
+ user.created
62
+ #=> 2020-06-16 21:59:04 -0400
63
+ ```
64
+
65
+ ### Guilds
66
+
67
+ Obtain information about guilds.
68
+
69
+ ```ruby
70
+ guild = Ruqqus.guild('Ruby')
71
+
72
+ # Query the number of members, description, accent color, etc.
73
+ guild.member_count
74
+ #=> 43
75
+
76
+ # Links to guild's banner, profile, etc.
77
+ guild.banner_url
78
+ #=> "https://i.ruqqus.com/board/ruby/banner-2.png"
79
+
80
+ # Check for flags such as NSFW, NSFL, deletion, banned, "offensive", etc.
81
+ guild.nsfw?
82
+ #=> false
83
+ ```
84
+
85
+ ### Posts
86
+
87
+ Obtain information about posts. The API functions for querying comments from a post are not yet implemented on the backend, so you will have to settle for web-scraping with `mechanize`, `nokogiri`, etc. if that information is needed.
88
+
89
+ ```ruby
90
+ post = Ruqqus.post('2e0x')
91
+ # ...or alternatively
92
+ post = Ruqqus::Post.from_url('https://ruqqus.com/post/2e0x/made-this-project-in-ruby-on')
34
93
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ruqqus.
94
+ # Obtain relevant information pertaining the guilds on Ruqqus
95
+
96
+ post.author_name
97
+ #=> "Galadriel"
98
+
99
+ post.title
100
+ #=> "Made this project in Ruby On Rails"
101
+
102
+ post.url
103
+ #=> "https://ruqqus-metrics.com/"
104
+
105
+ post.score
106
+ #=> 10
107
+ ```
108
+
109
+ ### Comments
110
+
111
+ Obtain information about comments. Comments are very similar to posts, but have a few unique methods for obtaining their nesting level, parent post/comment, etc.
112
+
113
+ ```ruby
114
+ comment = Ruqqus.comment('67mt')
115
+ # ...or alternatively
116
+ comment = Ruqqus::Comment.from_url('https://ruqqus.com/post/1wbo/hi-im-josh-roehl-singer-and/67mt')
117
+
118
+ comment.post.title
119
+ #=> "Hi. I'm Josh Roehl, singer and songwriter of the hit song \"Endless Summer\". I am hosting an AMA here."
120
+
121
+ comment.body
122
+ #=> "I'm fully aware that I'm not a very good singer. Let's call it half-singing, half-rapping."
123
+
124
+ comment.author.ban_reason
125
+ #=> "Spam"
126
+ ```
127
+
128
+ [Documentation](https://www.rubydoc.info/gems/ruqqus)
129
+
130
+ ## Contributing
36
131
 
132
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ForeverZer0/ruqqus.
37
133
 
38
134
  ## License
39
135
 
data/Rakefile CHANGED
@@ -1,10 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
3
2
 
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
8
- end
3
+ # Tests not implemented yet...
4
+ task(:test) { |_| true }
9
5
 
10
- task :default => :test
6
+ task default: :test
@@ -1,7 +1,125 @@
1
+ require 'rest-client'
2
+
3
+ require_relative 'ruqqus/item_base'
4
+ require_relative 'ruqqus/comment'
5
+ require_relative 'ruqqus/guild'
6
+ require_relative 'ruqqus/post'
7
+ require_relative 'ruqqus/user'
1
8
  require_relative 'ruqqus/version'
2
9
 
10
+ ##
11
+ # Top-level namespace of the Ruqqus gem.
3
12
  module Ruqqus
4
13
 
5
- class Error < StandardError; end
14
+ ##
15
+ # The base Ruqqus URL.
16
+ HOME = 'https://ruqqus.com'.freeze
17
+
18
+ ##
19
+ # The Ruqqus API version.
20
+ API_VERSION = 1
21
+
22
+ ##
23
+ # A regular expression used for username validation.
24
+ VALID_USERNAME = /^[a-zA-Z0-9_]{5,25}$/.freeze
25
+
26
+ ##
27
+ # A regular expression used for password validation.
28
+ VALID_PASSWORD= /^.{8,100}$/.freeze
29
+
30
+ ##
31
+ # A regular expression used for guild name validation.
32
+ VALID_GUILD = /^[a-zA-Z0-9][a-zA-Z0-9_]{2,24}$/.freeze
33
+
34
+ ##
35
+ # A regular expression used for post/comment ID validation.
36
+ VALID_POST = /[A-Za-z0-9]+/.freeze
6
37
 
38
+ ##
39
+ # Generic error class for exceptions specific to the Ruqqus API.
40
+ class Error < StandardError
41
+ end
42
+
43
+ ##
44
+ # Retrieves the {User} with the specified username.
45
+ #
46
+ # @param username [String] the username of the Ruqqus account to retrieve.
47
+ #
48
+ # @return [User] the requested {User}.
49
+ #
50
+ # @raise [ArgumentError] when `username` is `nil` or value does match the {VALID_USERNAME} regular expression.
51
+ # @raise [Error] thrown when user account does not exist.
52
+ def self.user(username)
53
+ raise(ArgumentError, 'username cannot be nil') unless username
54
+ raise(ArgumentError, 'invalid username') unless VALID_USERNAME.match?(username)
55
+ api_get("#{HOME}/api/v1/user/#{username}", User)
56
+ end
57
+
58
+ ##
59
+ # Retrieves the {Guild} with the specified name.
60
+ #
61
+ # @param guild_name [String] the name of the Ruqqus guild to retrieve.
62
+ #
63
+ # @return [Guild] the requested {Guild}.
64
+ #
65
+ # @raise [ArgumentError] when `guild_name` is `nil` or value does match the {VALID_GUILD} regular expression.
66
+ # @raise [Error] thrown when guild does not exist.
67
+ def self.guild(guild_name)
68
+ raise(ArgumentError, 'guild_name cannot be nil') unless guild_name
69
+ raise(ArgumentError, 'invalid guild name') unless VALID_POST.match?(guild_name)
70
+ api_get("#{HOME}/api/v1/guild/#{guild_name}", Guild)
71
+ end
72
+
73
+ ##
74
+ # Retrieves the {Post} with the specified name.
75
+ #
76
+ # @param post_id [String] the ID of the post to retrieve.
77
+ #
78
+ # @return [Post] the requested {Post}.
79
+ #
80
+ # @raise [ArgumentError] when `post_id` is `nil` or value does match the {VALID_POST} regular expression.
81
+ # @raise [Error] thrown when a post with the specified ID does not exist.
82
+ def self.post(post_id)
83
+ raise(ArgumentError, 'post_id cannot be nil') unless post_id
84
+ raise(ArgumentError, 'invalid post ID') unless VALID_POST.match?(post_id)
85
+ api_get("#{HOME}/api/v1/post/#{post_id}", Post)
86
+ end
87
+
88
+ ##
89
+ # Retrieves the {Comment} with the specified name.
90
+ #
91
+ # @param comment_id [String] the ID of the comment to retrieve.
92
+ #
93
+ # @return [Comment] the requested {Comment}.
94
+ #
95
+ # @raise [ArgumentError] when `comment_id` is `nil` or value does match the {VALID_POST} regular expression.
96
+ # @raise [Error] when a comment with the specified ID does not exist.
97
+ def self.comment(comment_id)
98
+ raise(ArgumentError, 'comment_id cannot be nil') unless comment_id
99
+ raise(ArgumentError, 'invalid comment ID') unless VALID_POST.match?(comment_id)
100
+ api_get("#{HOME}/api/v1/comment/#{comment_id}", Comment)
101
+ end
102
+
103
+ ##
104
+ # @api private
105
+ # Calls the GET method at the specified API route, and returns the deserializes JSON response as an object.
106
+ #
107
+ # @param route [String] the full API route to the GET method.
108
+ # @param klass [Class] a Class instance that is inherited from {ItemBase}.
109
+ #
110
+ # @return [Object] an instance of the specified class.
111
+ #
112
+ # @raise [Error] thrown when the requested item is not found.
113
+ # @raise [ArgumentError] when the specified class is not inherited from {ItemBase}.
114
+ def self.api_get(route, klass)
115
+ raise(ArgumentError, 'klass is not a child class of Ruqqus::ItemBase') unless klass < ItemBase
116
+ #noinspection RubyResolve
117
+ begin
118
+ response = RestClient.get(route)
119
+ klass.from_json(response.body)
120
+ rescue RestClient::BadRequest
121
+ raise(Error, 'invalid search parameters, object with specified criteria does not exist')
122
+ end
123
+ end
7
124
  end
125
+
@@ -0,0 +1,61 @@
1
+ module Ruqqus
2
+ ##
3
+ # Describes a trophy that can be earned/issued to an account for specific accomplishments.
4
+ class Badge
5
+
6
+ ##
7
+ # @!attribute [r] name
8
+ # @return [String?] the name of the badge.
9
+
10
+ ##
11
+ # @!attribute [r] text
12
+ # @return [String?] a brief description of the badge.
13
+
14
+ ##
15
+ # @!attribute [r] url
16
+ # @return [String?] the URL associated with the badge, or `nil` if not defined.
17
+
18
+ ##
19
+ # @!attribute [r] created_utc
20
+ # @return [Integer?] the time the badge was earned in seconds since the Unix epoch, or `0` if not defined.
21
+
22
+ ##
23
+ # @!attribute [r] created
24
+ # @return [Time?] the time the badge was earned, or `nil` if not defined.
25
+
26
+ ##
27
+ # Creates a new instance of the {Badge} class.
28
+ #
29
+ # @param data [Hash] the parsed JSON payload defining this instance.
30
+ def initialize(data)
31
+ @data = data || raise(ArgumentError, 'data cannot be nil')
32
+ end
33
+
34
+ def name
35
+ @data[:name]
36
+ end
37
+
38
+ def text
39
+ @data[:text]
40
+ end
41
+
42
+ def url
43
+ @data[:url]
44
+ end
45
+
46
+ def created_utc
47
+ @data[:created_utc]
48
+ end
49
+
50
+ def created
51
+ #noinspection RubyYardReturnMatch
52
+ @data[:created_utc] ? Time.at(@data[:created_utc]) : nil
53
+ end
54
+
55
+ ##
56
+ # @return [String] the string representation of the object.
57
+ def to_s
58
+ @data[:text] || inspect
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ require_relative 'submission'
2
+
3
+ module Ruqqus
4
+
5
+ ##
6
+ # Describes a comment in a post.
7
+ class Comment < Submission
8
+
9
+ ##
10
+ # Captures the ID of a comment from a Ruqqus URL
11
+ COMMENT_REGEX = /ruqqus.com\/post\/.+\/.+\/([A-Za-z0-9]+)\/?/.freeze
12
+
13
+ ##
14
+ # @return [Integer] the level of "nesting" in the comment tree, starting at `1` when in direct reply to the post.
15
+ def level
16
+ @data[:level]
17
+ end
18
+
19
+ ##
20
+ # @return [String] the unique ID of the parent for this comment.
21
+ def parent_id
22
+ @data[:parent]
23
+ end
24
+
25
+ ##
26
+ # @return [Post,Comment] the parent for this content.
27
+ def parent
28
+ #noinspection RubyYardReturnMatch
29
+ @parent ||= level > 1 ? Ruqqus.comment(parent_id) : Ruqqus.post(parent_id)
30
+ end
31
+
32
+ ##
33
+ # @return [String] the ID of the post this comment belongs to.
34
+ def post_id
35
+ @data[:post]
36
+ end
37
+
38
+ ##
39
+ # @return [Post] the post this comment belongs to.
40
+ def post
41
+ #noinspection RubyYardReturnMatch
42
+ Ruqqus.post(post_id)
43
+ end
44
+
45
+ ##
46
+ # Creates a new {Comment} instance from the specified URL.
47
+ #
48
+ # @param url [String] a URL link to a comment.
49
+ #
50
+ # @return [Comment] the {Comment} instance the URL links to.
51
+ #
52
+ # @raise [ArgumentError] then `url` is `nil`.
53
+ # @raise [Ruqqus::Error] when the link is not for a Ruqqus comment.
54
+ def self.from_url(url)
55
+ raise(ArgumentError, 'url cannot be nil') unless url
56
+ match = COMMENT_REGEX.match(url)
57
+ raise(ArgumentError, 'invalid URL for a comment') unless match
58
+ Ruqqus.comment($1)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,85 @@
1
+ module Ruqqus
2
+
3
+ ##
4
+ # Represents a Ruqqus guild.
5
+ class Guild < ItemBase
6
+
7
+ ##
8
+ # @return [String] the name of the guild.
9
+ def name
10
+ @data[:name]
11
+ end
12
+
13
+ ##
14
+ # @return [Integer] the number of members subscribed to the guild.
15
+ def member_count
16
+ @data[:subscriber_count]&.to_i || 0
17
+ end
18
+
19
+ ##
20
+ # @return [Integer] the number of guild masters who moderate this guild.
21
+ def gm_count
22
+ @data[:mods_count]&.to_i || 0
23
+ end
24
+
25
+ ##
26
+ # @return [String] the full ID of the guild.
27
+ def full_name
28
+ @data[:fullname]
29
+ end
30
+
31
+ ##
32
+ # @return [Boolean] `true` if the guild contains adult content and flagged as NSFW, otherwise `false`.
33
+ def nsfw?
34
+ @data[:over_18]
35
+ end
36
+
37
+ ##
38
+ # @return [Boolean] `true` if guild is private and required membership to view content, otherwise `false`.
39
+ def private?
40
+ !!@data[:is_private]
41
+ end
42
+
43
+ ##
44
+ # @return [Boolean] `true` if posting is restricted byy guild masters, otherwise `false`.
45
+ def restricted?
46
+ !!@data[:is_restricted]
47
+ end
48
+
49
+ ##
50
+ # @return [String] the description of the guild.
51
+ def description
52
+ @data[:description]
53
+ end
54
+
55
+ ##
56
+ # @return [String] the description of the guild in HTML format.
57
+ def description_html
58
+ @data[:description_html]
59
+ end
60
+
61
+ ##
62
+ # @return [String] the URL for the banner image associated with the guild.
63
+ def banner_url
64
+ @data[:banner_url]
65
+ end
66
+
67
+ ##
68
+ # @return [String] the URL for the profile image associated with the guild.
69
+ def profile_url
70
+ @data[:profile_url]
71
+ end
72
+
73
+ ##
74
+ # @return [String] the accent color used for the guild, in HTML format.
75
+ def color
76
+ @data[:color]
77
+ end
78
+
79
+ ##
80
+ # @return [String] the string representation of the object.
81
+ def to_s
82
+ @data[:name] || inspect
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,58 @@
1
+ require 'json'
2
+
3
+ module Ruqqus
4
+
5
+ ##
6
+ # @abstract
7
+ # Base class for all all major API types.
8
+ class ItemBase
9
+
10
+ ##
11
+ # @return [Boolean] `true` if item has been banned, otherwise `false`.
12
+ def banned?
13
+ !!@data[:is_banned]
14
+ end
15
+
16
+ ##
17
+ # @return [Integer] the time the item was created, in seconds since the Unix epoch.
18
+ def created_utc
19
+ @data[:created_utc]
20
+ end
21
+
22
+ ##
23
+ # @return [Time] the time the item was created.
24
+ def created
25
+ Time.at(created_utc)
26
+ end
27
+
28
+ ##
29
+ # @return [String] a unique ID for this item.
30
+ def id
31
+ @data[:id]
32
+ end
33
+
34
+ ##
35
+ # @return [Boolean] `true` if this object is equal to another, otherwise `false`.
36
+ def ==(other)
37
+ self.class == other.class && id == other.id
38
+ end
39
+
40
+ ##
41
+ # @return [String] a relative link to this item.
42
+ def permalink
43
+ @data[:permalink]
44
+ end
45
+
46
+ ##
47
+ # Loads the object from a JSON-formatted string.
48
+ #
49
+ # @return [Object] the loaded object.
50
+ def self.from_json(json)
51
+ obj = allocate
52
+ obj.instance_variable_set(:@data, JSON.parse(json, symbolize_names: true))
53
+ obj
54
+ end
55
+
56
+ private_class_method :new
57
+ end
58
+ end
@@ -0,0 +1,85 @@
1
+ require_relative 'submission'
2
+
3
+ module Ruqqus
4
+
5
+ ##
6
+ # Represents a post on Ruqqus.
7
+ class Post < Submission
8
+
9
+ ##
10
+ # Captures the ID of a post from a Ruqqus URL
11
+ POST_REGEX = /ruqqus.com\/post\/([A-Za-z0-9]+)\/?.*/.freeze
12
+
13
+ ##
14
+ # @return [Title?] the title assigned to the author, or `nil` if none is defined.
15
+ def author_title
16
+ #noinspection RubyYardReturnMatch
17
+ @author_title ||= @data[:author_title] ? Title.new(@data[:author_title]) : nil
18
+ end
19
+
20
+ ##
21
+ # @return [Integer] the number of comments made on the post.
22
+ def comment_count
23
+ @data[:comment_count]
24
+ end
25
+
26
+ ##
27
+ # @return [String] the domain name for link posts, otherwise a short descriptor of the post type.
28
+ def domain
29
+ @data[:domain]
30
+ end
31
+
32
+ ##
33
+ # @return [String] the embed URL for the post.
34
+ def embed_url
35
+ @data[:embed_url]
36
+ end
37
+
38
+ ##
39
+ # @return [String] the name of the guild this post was originally posted in.
40
+ def original_guild_name
41
+ @data[:original_guild_name]
42
+ end
43
+
44
+ ##
45
+ # @return [Guild] the guild this post was originally posted in.
46
+ def original_guild
47
+ @original_guild ||= Ruqqus.guild(original_guild_name)
48
+ end
49
+
50
+ ##
51
+ # @return [String?] the URL of the post's thumbnail image, or `nil` if none exists.
52
+ def thumb_url
53
+ @data[:thumb_url]
54
+ end
55
+
56
+ ##
57
+ # @return [String?] the URL the post links to, or `nil` if none is specified.
58
+ def url
59
+ #noinspection RubyYardReturnMatch
60
+ @data[:url]&.empty? ? nil : @data[:url]
61
+ end
62
+
63
+ ##
64
+ # @return [String] the string representation of the object.
65
+ def to_s
66
+ @data[:title] || inspect
67
+ end
68
+
69
+ ##
70
+ # Creates a new {Post} instance from the specified URL.
71
+ #
72
+ # @param url [String] a URL link to a post.
73
+ #
74
+ # @return [Post] the {Post} instance the URL links to.
75
+ #
76
+ # @raise [ArgumentError] then `url` is `nil`.
77
+ # @raise [Ruqqus::Error] when the link is not for a Ruqqus post.
78
+ def self.from_url(url)
79
+ raise(ArgumentError, 'url cannot be nil') unless url
80
+ match = POST_REGEX.match(url)
81
+ raise(ArgumentError, 'invalid URL for a post') unless match
82
+ Ruqqus.post($1)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,132 @@
1
+ require_relative 'item_base'
2
+
3
+ module Ruqqus
4
+
5
+ ##
6
+ # @abstract
7
+ # Base class for {Post} and {Comment} types.
8
+ class Submission < ItemBase
9
+
10
+ ##
11
+ # @return [String?] the name of the creator of the item, or `nil` if deleted account.
12
+ def author_name
13
+ @data[:author]
14
+ end
15
+
16
+ ##
17
+ # @return [String] the creator of the item, or `nil` if deleted account.
18
+ def author
19
+ #noinspection RubyYardReturnMatch
20
+ @author ||= author_name ? Ruqqus.user(author_name) : nil
21
+ end
22
+
23
+ ##
24
+ # @return [String] the text body of the item.
25
+ def body
26
+ @data[:body]
27
+ end
28
+
29
+ ##
30
+ # @return [String] the text body of the item in HTML format.
31
+ def body_html
32
+ @data[:body_html]
33
+ end
34
+
35
+ ##
36
+ # @return [Integer] the time of the last edit in seconds since the Unix epoch, or `0` if never edited.
37
+ def last_edit_utc
38
+ @data[:edited_utc]
39
+ end
40
+
41
+ ##
42
+ # @return [Time] the time of the last edit.
43
+ def last_edit
44
+ Time.at(@data[:edited_utc])
45
+ end
46
+
47
+ ##
48
+ # @return [Boolean] `true` if post has been edited, otherwise `false`.
49
+ def edited?
50
+ @data[:edited_utc] != 0
51
+ end
52
+
53
+ ##
54
+ # @return [Integer] the number of upvotes this item has received.
55
+ def upvotes
56
+ @data[:upvotes]
57
+ end
58
+
59
+ ##
60
+ # @return [Integer] the number of downvotes this item has received.
61
+ def downvotes
62
+ @data[:downvotes]
63
+ end
64
+
65
+ ##
66
+ # @return [Integer] a score calculated by adding upvotes and subtracting downvotes.
67
+ def score
68
+ @data[:score]
69
+ end
70
+
71
+ ##
72
+ # @return [Boolean] `true` if item is adult content and flagged as NSFW, otherwise `false`.
73
+ def nsfw?
74
+ !!@data[:is_nsfw]
75
+ end
76
+
77
+ ##
78
+ # @return [Boolean] `true` if item is adult content and flagged as NSFL, otheriwse `false`.
79
+ def nsfl?
80
+ !!@data[:is_nsfl]
81
+ end
82
+
83
+ ##
84
+ # @return [Boolean] `true` if item has been archived, otherwise `false`.
85
+ def archived?
86
+ !!@data[:is_archived]
87
+ end
88
+
89
+ ##
90
+ # @return [Boolean] `true` if item has been deleted, otherwise `false`.
91
+ def deleted?
92
+ !!@data[:is_deleted]
93
+ end
94
+
95
+ ##
96
+ # @return [Boolean] `true` if item has been classified has offensive, otherwise `false`.
97
+ def offensive?
98
+ !!@data[:is_offensive]
99
+ end
100
+
101
+ ##
102
+ # @return [String] the full ID of this item.
103
+ def full_name
104
+ @data[:fullname]
105
+ end
106
+
107
+ ##
108
+ # @return [String] the name of the guild this item is contained within.
109
+ def guild_name
110
+ @data[:guild_name]
111
+ end
112
+
113
+ ##
114
+ # @return [Guild?] the guild this item is contained within.
115
+ def guild
116
+ #noinspection RubyYardReturnMatch
117
+ @guild ||= guild_name ? Ruqqus.guild(guild_name) : nil
118
+ end
119
+
120
+ ##
121
+ # @return [String] a unique ID associated with this item.
122
+ def id
123
+ @data[:id]
124
+ end
125
+
126
+ ##
127
+ # @return [String] the name/title of this item.
128
+ def title
129
+ @data[:title]
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,48 @@
1
+
2
+ module Ruqqus
3
+
4
+ ##
5
+ # Describes a title associated with a username.
6
+ class Title
7
+
8
+ ##
9
+ # @!attribute [r] id
10
+ # @return [Integer] a unique ID associated with this title.
11
+
12
+ ##
13
+ # @!attribute [r] text
14
+ # @return [String] the text value of the title.
15
+
16
+ ##
17
+ # @!attribute [r] color
18
+ # @return [String] the color used to display the title in HTML format.
19
+
20
+ ##
21
+ # @!attribute [r] kind
22
+ # @return [Integer] an integer determining the "rank" of the title.
23
+
24
+ ##
25
+ # Creates a new instance of the {Title} class.
26
+ #
27
+ # @param data [Hash] the parsed JSON payload defining this instance.
28
+ def initialize(data)
29
+ @data = data || raise(ArgumentError, 'data cannot be nil')
30
+ end
31
+
32
+ def id
33
+ @data[:id]
34
+ end
35
+
36
+ def text
37
+ @data[:text]
38
+ end
39
+
40
+ def color
41
+ @data[:color]
42
+ end
43
+
44
+ def kind
45
+ @data[:kind]
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,96 @@
1
+ require_relative 'badge'
2
+ require_relative 'title'
3
+ require_relative 'item_base'
4
+
5
+ module Ruqqus
6
+
7
+ ##
8
+ # Represents a Ruqqus user account.
9
+ class User < ItemBase
10
+
11
+ ##
12
+ # @return [Integer] the number of comments the user has created.
13
+ def comment_count
14
+ @data[:comment_count] || 0
15
+ end
16
+
17
+ ##
18
+ # @return [Integer] the number of posts the user has created.
19
+ def post_count
20
+ @data[:post_count] || 0
21
+ end
22
+
23
+ ##
24
+ # @return [Integer] the amount of rep the user has earned from comments.
25
+ def comment_rep
26
+ @data[:comment_rep] || 0
27
+ end
28
+
29
+ ##
30
+ # @return [Integer] the amount of rep the user has earned from posts.
31
+ def post_rep
32
+ @data[:post_rep] || 0
33
+ end
34
+
35
+ ##
36
+ # @return [Integer] the total amount of rep the user has earned from comments and posts.
37
+ def total_rep
38
+ comment_rep + post_rep
39
+ end
40
+
41
+ ##
42
+ # @return [String] the username of the account.
43
+ def username
44
+ @data[:username]
45
+ end
46
+
47
+ ##
48
+ # @return [Array<Badge>] an array of badges associated with this account.
49
+ def badges
50
+ @badges ||= @data[:badges].map { |b| Badge.new(b) }
51
+ end
52
+
53
+ ##
54
+ # @return [Title?] the title the user has associated with their account, or `nil` if none is assigned.
55
+ def title
56
+ #noinspection RubyYardReturnMatch
57
+ @title ||= @data[:title] ? Title.new(@data[title]) : nil
58
+ end
59
+
60
+ ##
61
+ # @return [String] the URL for the banner image associated with the account.
62
+ def banner_url
63
+ @data[:banner_url]
64
+ end
65
+
66
+ ##
67
+ # @return [String] the URL for the profile image associated with the account.
68
+ def profile_url
69
+ @data[:profile_url]
70
+ end
71
+
72
+ ##
73
+ # @return [String] A brief statement/biography the user has associated with their account.
74
+ def bio
75
+ @data[:bio]
76
+ end
77
+
78
+ ##
79
+ # @return [String] a brief statement/biography the user has associated with their account in HTML format.
80
+ def bio_html
81
+ @data[:bio_html]
82
+ end
83
+
84
+ ##
85
+ # @return [String?] the reason the user was banned if they were, otherwise `nil`.
86
+ def ban_reason
87
+ @data[:ban_reason]
88
+ end
89
+
90
+ ##
91
+ # @return [String] the string representation of the object.
92
+ def to_s
93
+ @data[:username] || inspect
94
+ end
95
+ end
96
+ end
@@ -1,3 +1,12 @@
1
1
  module Ruqqus
2
- VERSION = "0.1.0"
2
+
3
+ ##
4
+ # The Ruqqus gem version.
5
+ VERSION = '1.0.0'.freeze
6
+
7
+ ##
8
+ # Lulz
9
+ ENDLESS_SUMMER = 'https://youtu.be/o_LskiXQ73c'.freeze
10
+
11
+ private_constant(:ENDLESS_SUMMER)
3
12
  end
@@ -2,20 +2,24 @@ require_relative 'lib/ruqqus/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
 
5
+ # Required specifications
5
6
  spec.name = 'ruqqus'
6
7
  spec.version = Ruqqus::VERSION
7
8
  spec.authors = ['ForeverZer0']
8
9
  spec.email = ['efreed09@gmail.com']
9
-
10
- spec.summary = %q{Base library for interacting with the ruqqus.com API.}
11
- spec.description = %q{Base library for interacting with the ruqqus.com API.}
10
+ spec.summary = %q{A Ruby API implementation for Ruqqus, an open-source platform for online communities, free of censorship and moderator abuse by design.}
11
+ spec.description = %q{A Ruby API implementation for Ruqqus, an open-source platform for online communities, free of censorship and moderator abuse by design. While platform is still in Beta at this time and the public API for it is still quite limited, this gem will be actively updated as it continues to grow and is developed.}
12
12
  spec.homepage = 'https://github.com/ForeverZer0/ruqqus'
13
13
  spec.license = 'MIT'
14
14
  spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
15
15
 
16
- spec.metadata['homepage_uri'] = spec.homepage
17
- spec.metadata['source_code_uri'] = 'https://github.com/ForeverZer0/ruqqus'
18
- spec.metadata['changelog_uri'] = 'https://github.com/ForeverZer0/ruqqus/CHANGELOG.md'
16
+ # Metadata
17
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/ForeverZer0/ruqqus'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/ForeverZer0/ruqqus/CHANGELOG.md'
21
+ spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/ruqqus'
22
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/ForeverZer0/ruqqus/issues'
19
23
 
20
24
  # Specify which files should be added to the gem when it is released.
21
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -23,9 +27,14 @@ Gem::Specification.new do |spec|
23
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
28
  end
25
29
 
30
+ # Register executables (none yet...)
26
31
  spec.bindir = 'exe'
27
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
33
  spec.require_paths = ['lib']
29
34
 
30
- spec.add_runtime_dependency('nokogiri', '~> 1.10')
35
+ # Dependencies
36
+ spec.add_runtime_dependency('rest-client', '~> 2.1')
37
+
38
+ spec.add_development_dependency('rake', '~> 13.0')
39
+ spec.add_development_dependency('yard', '~> 0.9')
31
40
  end
metadata CHANGED
@@ -1,30 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruqqus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ForeverZer0
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-25 00:00:00.000000000 Z
11
+ date: 2020-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: nokogiri
14
+ name: rest-client
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '2.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
27
- description: Base library for interacting with the ruqqus.com API.
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ description: A Ruby API implementation for Ruqqus, an open-source platform for online
56
+ communities, free of censorship and moderator abuse by design. While platform is
57
+ still in Beta at this time and the public API for it is still quite limited, this
58
+ gem will be actively updated as it continues to grow and is developed.
28
59
  email:
29
60
  - efreed09@gmail.com
30
61
  executables: []
@@ -33,6 +64,7 @@ extra_rdoc_files: []
33
64
  files:
34
65
  - ".gitignore"
35
66
  - ".travis.yml"
67
+ - ".yardopts"
36
68
  - CHANGELOG.md
37
69
  - Gemfile
38
70
  - LICENSE.txt
@@ -41,15 +73,26 @@ files:
41
73
  - bin/console
42
74
  - bin/setup
43
75
  - lib/ruqqus.rb
76
+ - lib/ruqqus/badge.rb
77
+ - lib/ruqqus/comment.rb
78
+ - lib/ruqqus/guild.rb
79
+ - lib/ruqqus/item_base.rb
80
+ - lib/ruqqus/post.rb
81
+ - lib/ruqqus/submission.rb
82
+ - lib/ruqqus/title.rb
83
+ - lib/ruqqus/user.rb
44
84
  - lib/ruqqus/version.rb
45
85
  - ruqqus.gemspec
46
86
  homepage: https://github.com/ForeverZer0/ruqqus
47
87
  licenses:
48
88
  - MIT
49
89
  metadata:
90
+ allowed_push_host: https://rubygems.org
50
91
  homepage_uri: https://github.com/ForeverZer0/ruqqus
51
92
  source_code_uri: https://github.com/ForeverZer0/ruqqus
52
93
  changelog_uri: https://github.com/ForeverZer0/ruqqus/CHANGELOG.md
94
+ documentation_uri: https://www.rubydoc.info/gems/ruqqus
95
+ bug_tracker_uri: https://github.com/ForeverZer0/ruqqus/issues
53
96
  post_install_message:
54
97
  rdoc_options: []
55
98
  require_paths:
@@ -68,5 +111,6 @@ requirements: []
68
111
  rubygems_version: 3.1.4
69
112
  signing_key:
70
113
  specification_version: 4
71
- summary: Base library for interacting with the ruqqus.com API.
114
+ summary: A Ruby API implementation for Ruqqus, an open-source platform for online
115
+ communities, free of censorship and moderator abuse by design.
72
116
  test_files: []