diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index a9def4743..0a983fd42 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -28,10 +28,10 @@ jobs: sudo apt update sudo apt install -y git openssh-client - - name: Setup Ruby 2.7 + - name: Setup Ruby 3.0 uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.0' bundler-cache: true - name: Checkout repository for Github Pages diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 3103db5f8..0e5b0dbfb 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - versions: [ '2.7', '3.0', '3.1', '3.2', '3.3' ] + versions: [ '3.0', '3.1', '3.2', '3.3' ] steps: - name: Checkout repository diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index bf1634633..dd541120f 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -22,10 +22,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - - name: Setup Ruby 2.7 + - name: Setup Ruby 3.0 uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.0' bundler-cache: true - name: Run bundle install diff --git a/.github/workflows/yard.yml b/.github/workflows/yard.yml index 1b7cea63f..0f006d274 100644 --- a/.github/workflows/yard.yml +++ b/.github/workflows/yard.yml @@ -22,10 +22,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - - name: Setup Ruby 2.7 + - name: Setup Ruby 3.0 uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.0' bundler-cache: true - name: Run bundle install diff --git a/.rubocop.yml b/.rubocop.yml index cbe94c83a..06a88b61d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,7 +8,7 @@ inherit_mode: AllCops: NewCops: enable - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.0 # Disable line length checks Layout/LineLength: @@ -66,3 +66,11 @@ Style/SingleLineBlockParams: Methods: - reduce: [m, e] - inject: [m, e] + +# Rule to keep development dependencies inside gemspec file +Gemspec/DevelopmentDependencies: + EnforcedStyle: gemspec + +# Rule disabled to avoid breaking methods or behaviors unnecessarily (Reactivate if you find it relevant) +Style/ReturnNilInPredicateMethodDefinition: + Enabled: false \ No newline at end of file diff --git a/README.md b/README.md index 5dc2196e5..e1f844e60 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ If you enjoy using the library, consider getting involved with the community to ## Dependencies -* Ruby >= 2.7 supported +* Ruby >= 3.0 supported * An installed build system for native extensions (on Windows, make sure you download the "Ruby+Devkit" version of [RubyInstaller](https://rubyinstaller.org/downloads/)) ### Voice dependencies diff --git a/discordrb-webhooks.gemspec b/discordrb-webhooks.gemspec index 7705c97f8..1036ab065 100644 --- a/discordrb-webhooks.gemspec +++ b/discordrb-webhooks.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'rest-client', '>= 2.0.0' - spec.required_ruby_version = '>= 2.7' + spec.required_ruby_version = '>= 3.0' spec.metadata = { 'rubygems_mfa_required' => 'true' } diff --git a/discordrb.gemspec b/discordrb.gemspec index bba67e037..51e25e8aa 100644 --- a/discordrb.gemspec +++ b/discordrb.gemspec @@ -31,17 +31,17 @@ Gem::Specification.new do |spec| spec.add_dependency 'discordrb-webhooks', '~> 3.5.0' - spec.required_ruby_version = '>= 2.7' + spec.required_ruby_version = '>= 3.0' spec.add_development_dependency 'bundler', '>= 1.10', '< 3' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'redcarpet', '~> 3.6.0' # YARD markdown formatting spec.add_development_dependency 'rspec', '~> 3.12.0' - spec.add_development_dependency 'rspec_junit_formatter', '~> 0.5.1' + spec.add_development_dependency 'rspec_junit_formatter', '~> 0.6.0' spec.add_development_dependency 'rspec-prof', '~> 0.0.7' - spec.add_development_dependency 'rubocop', '~> 1.36.0' + spec.add_development_dependency 'rubocop', '~> 1.59.0' spec.add_development_dependency 'rubocop-performance', '~> 1.0' spec.add_development_dependency 'rubocop-rake', '~> 0.6.0' - spec.add_development_dependency 'simplecov', '~> 0.21.0' + spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9.9' end diff --git a/examples/channel_overwrite.rb b/examples/channel_overwrite.rb index 4723f577e..a65d95ce9 100644 --- a/examples/channel_overwrite.rb +++ b/examples/channel_overwrite.rb @@ -49,7 +49,7 @@ puts(event.bot.channel(CHANNEL_EDIT, event.server).permission_overwrites.map { |_, v| "#{v.type} - #{v.id} - #{v.allow.bits} / #{v.deny.bits}" }) # Bulk edit from permission_overwrites return values (this method return a Hash and not an Array) - event.bot.channel(CHANNEL_EDIT, event.server).permission_overwrites = event.bot.channel(CHANNEL_EDIT, event.server).permission_overwrites + event.bot.channel(CHANNEL_EDIT, event.server).permission_overwrites = event.bot.channel(CHANNEL_EDIT, event.server).permission_overwrites # rubocop:disable Lint/SelfAssignment puts(event.bot.channel(CHANNEL_EDIT, event.server).permission_overwrites.map { |_, v| "#{v.type} - #{v.id} - #{v.allow.bits} / #{v.deny.bits}" }) # Send nil to check if permission_overwrites not changed diff --git a/lib/discordrb/bot.rb b/lib/discordrb/bot.rb index 84bc987f3..1f1b83de2 100644 --- a/lib/discordrb/bot.rb +++ b/lib/discordrb/bot.rb @@ -339,7 +339,7 @@ def voice(thing) return nil unless channel server_id = channel.server.id - return @voices[server_id] if @voices[server_id] + @voices[server_id] end # Connects to a voice channel, initializes network connections and returns the {Voice::VoiceBot} over which audio @@ -1396,7 +1396,7 @@ def handle_dispatch(type, data) new_activities = (data['activities'] || []).map { |act_data| Activity.new(act_data, self) } presence_user = @users[data['user']['id'].to_i] - old_activities = (presence_user&.activities || []) + old_activities = presence_user&.activities || [] update_presence(data) # Starting a new game @@ -1700,7 +1700,7 @@ def call_event(handler, event) def handle_awaits(event) @awaits ||= {} - @awaits.each do |_, await| + @awaits.each_value do |await| key, should_delete = await.match(event) next unless key diff --git a/lib/discordrb/commands/parser.rb b/lib/discordrb/commands/parser.rb index 2d9574690..d96f21778 100644 --- a/lib/discordrb/commands/parser.rb +++ b/lib/discordrb/commands/parser.rb @@ -159,7 +159,7 @@ def execute_bare(event) escaped = false hacky_delim, hacky_space, hacky_prev, hacky_newline = [0xe001, 0xe002, 0xe003, 0xe004].pack('U*').chars - @chain.each_char.each_with_index do |char, index| + @chain.each_char.with_index do |char, index| # Escape character if char == '\\' && !escaped escaped = true diff --git a/lib/discordrb/data/component.rb b/lib/discordrb/data/component.rb index 035e22680..409166651 100644 --- a/lib/discordrb/data/component.rb +++ b/lib/discordrb/data/component.rb @@ -100,7 +100,7 @@ def initialize(data, bot) # @method link? # @return [true, false] Webhooks::View::BUTTON_STYLES.each do |name, value| - define_method("#{name}?") do + define_method(:"#{name}?") do @style == value end end diff --git a/lib/discordrb/data/embed.rb b/lib/discordrb/data/embed.rb index 546c57bd7..578285700 100644 --- a/lib/discordrb/data/embed.rb +++ b/lib/discordrb/data/embed.rb @@ -68,7 +68,7 @@ def initialize(data, message) @provider = data['provider'].nil? ? nil : EmbedProvider.new(data['provider'], self) @thumbnail = data['thumbnail'].nil? ? nil : EmbedThumbnail.new(data['thumbnail'], self) @author = data['author'].nil? ? nil : EmbedAuthor.new(data['author'], self) - @fields = data['fields'].nil? ? nil : data['fields'].map { |field| EmbedField.new(field, self) } + @fields = data['fields']&.map { |field| EmbedField.new(field, self) } end end diff --git a/lib/discordrb/data/emoji.rb b/lib/discordrb/data/emoji.rb index dc26aee58..5d81d7183 100644 --- a/lib/discordrb/data/emoji.rb +++ b/lib/discordrb/data/emoji.rb @@ -25,7 +25,7 @@ def initialize(data, bot, server = nil) @name = data['name'] @server = server - @id = data['id'].nil? ? nil : data['id'].to_i + @id = data['id']&.to_i @animated = data['animated'] process_roles(data['roles']) if server diff --git a/lib/discordrb/data/interaction.rb b/lib/discordrb/data/interaction.rb index 2e3b16561..02b0a4968 100644 --- a/lib/discordrb/data/interaction.rb +++ b/lib/discordrb/data/interaction.rb @@ -76,7 +76,7 @@ def initialize(data, bot) end @token = data['token'] @version = data['version'] - @components = @data['components']&.map { |component| Components.from_data(component, @bot) }&.compact || [] + @components = @data['components']&.filter_map { |component| Components.from_data(component, @bot) } || [] end # Respond to the creation of this interaction. An interaction must be responded to or deferred, diff --git a/lib/discordrb/data/member.rb b/lib/discordrb/data/member.rb index 0d5a3f8bb..f2cc80b2f 100644 --- a/lib/discordrb/data/member.rb +++ b/lib/discordrb/data/member.rb @@ -64,7 +64,7 @@ def initialize(data, server, bot) @bot = bot @user = bot.ensure_user(data['user']) - super @user # Initialize the delegate class + super(@user) # Initialize the delegate class @server = server @server_id = server&.id || data['guild_id'].to_i diff --git a/lib/discordrb/data/message.rb b/lib/discordrb/data/message.rb index 4066f512b..3e512aa6a 100644 --- a/lib/discordrb/data/message.rb +++ b/lib/discordrb/data/message.rb @@ -198,7 +198,7 @@ def respond(content, tts = false, embed = nil, attachments = nil, allowed_mentio # @return [Message] the resulting message. def edit(new_content, new_embeds = nil, new_components = nil) new_embeds = (new_embeds.instance_of?(Array) ? new_embeds.map(&:to_hash) : [new_embeds&.to_hash]).compact - new_components = new_components&.to_a || [] + new_components = new_components.to_a response = API::Channel.edit_message(@bot.token, @channel.id, @id, new_content, [], new_embeds, new_components) Message.new(JSON.parse(response), @bot) diff --git a/lib/discordrb/data/reaction.rb b/lib/discordrb/data/reaction.rb index 202d5795b..491f5eb49 100644 --- a/lib/discordrb/data/reaction.rb +++ b/lib/discordrb/data/reaction.rb @@ -19,7 +19,7 @@ class Reaction def initialize(data) @count = data['count'] @me = data['me'] - @id = data['emoji']['id'].nil? ? nil : data['emoji']['id'].to_i + @id = data['emoji']['id']&.to_i @name = data['emoji']['name'] end diff --git a/lib/discordrb/data/recipient.rb b/lib/discordrb/data/recipient.rb index 600c7356f..e0c046256 100644 --- a/lib/discordrb/data/recipient.rb +++ b/lib/discordrb/data/recipient.rb @@ -16,7 +16,7 @@ def initialize(user, channel, bot) raise ArgumentError, 'Tried to create a recipient for a public channel!' unless @channel.private? @user = user - super @user + super(@user) # Member attributes @mute = @deaf = @self_mute = @self_deaf = false diff --git a/lib/discordrb/data/server.rb b/lib/discordrb/data/server.rb index b868e9e84..71a538559 100644 --- a/lib/discordrb/data/server.rb +++ b/lib/discordrb/data/server.rb @@ -397,7 +397,7 @@ def add_role(role) # @!visibility private def delete_role(role_id) @roles.reject! { |r| r.id == role_id } - @members.each do |_, member| + @members.each_value do |member| new_roles = member.roles.reject { |r| r.id == role_id } member.update_roles(new_roles) end @@ -515,7 +515,7 @@ def create_channel(name, type = 0, topic: nil, bitrate: nil, user_limit: nil, pe # @param reason [String] The reason the for the creation of this role. # @return [Role] the created role. def create_role(name: 'new role', colour: 0, hoist: false, mentionable: false, permissions: 104_324_161, reason: nil) - colour = colour.respond_to?(:combined) ? colour.combined : colour + colour = colour.combined if colour.respond_to?(:combined) permissions = if permissions.is_a?(Array) Permissions.bits(permissions) @@ -830,11 +830,11 @@ def update_data(new_data = nil) @afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout'] || @afk_timeout afk_channel_id = new_data[:afk_channel_id] || new_data['afk_channel_id'] || @afk_channel - @afk_channel_id = afk_channel_id.nil? ? nil : afk_channel_id.resolve_id + @afk_channel_id = afk_channel_id&.resolve_id widget_channel_id = new_data[:widget_channel_id] || new_data['widget_channel_id'] || @widget_channel - @widget_channel_id = widget_channel_id.nil? ? nil : widget_channel_id.resolve_id + @widget_channel_id = widget_channel_id&.resolve_id system_channel_id = new_data[:system_channel_id] || new_data['system_channel_id'] || @system_channel - @system_channel_id = system_channel_id.nil? ? nil : system_channel_id.resolve_id + @system_channel_id = system_channel_id&.resolve_id @widget_enabled = new_data[:widget_enabled] || new_data['widget_enabled'] @splash = new_data[:splash_id] || new_data['splash_id'] || @splash_id diff --git a/lib/discordrb/data/user.rb b/lib/discordrb/data/user.rb index b7be8500d..861794f96 100644 --- a/lib/discordrb/data/user.rb +++ b/lib/discordrb/data/user.rb @@ -90,7 +90,7 @@ def avatar_url(format = nil) attr_reader :public_flags FLAGS.each do |name, value| - define_method("#{name}?") do + define_method(:"#{name}?") do (@public_flags & value).positive? end end @@ -233,7 +233,7 @@ def process_client_status(client_status) # @!method dnd? # @return [true, false] whether this user is set to do not disturb. %i[offline idle online dnd].each do |e| - define_method("#{e}?") do + define_method(:"#{e}?") do @status.to_sym == e end end diff --git a/lib/discordrb/permissions.rb b/lib/discordrb/permissions.rb index b9194bde7..a9af116cb 100644 --- a/lib/discordrb/permissions.rb +++ b/lib/discordrb/permissions.rb @@ -52,7 +52,7 @@ class Permissions FLAGS.each do |position, flag| attr_reader flag - define_method "can_#{flag}=" do |value| + define_method :"can_#{flag}=" do |value| new_bits = @bits if value new_bits |= (1 << position) @@ -81,7 +81,7 @@ def bits=(bits) def init_vars FLAGS.each do |position, flag| flag_set = ((@bits >> position) & 0x1) == 1 - instance_variable_set "@#{flag}", flag_set + instance_variable_set :"@#{flag}", flag_set end end @@ -194,7 +194,7 @@ def defined_permission?(action, channel = nil) # Define methods for querying permissions Discordrb::Permissions::FLAGS.each_value do |flag| - define_method "can_#{flag}?" do |channel = nil| + define_method :"can_#{flag}?" do |channel = nil| permission? flag, channel end end @@ -220,7 +220,7 @@ def defined_role_permission?(action, channel) false else # Otherwise defer to the role - role.permissions.instance_variable_get("@#{action}") || can_act + role.permissions.instance_variable_get(:"@#{action}") || can_act end end end @@ -232,9 +232,9 @@ def permission_overwrite(action, channel, id) # Otherwise, check the allow and deny objects allow = channel.permission_overwrites[id].allow deny = channel.permission_overwrites[id].deny - if allow.instance_variable_get("@#{action}") + if allow.instance_variable_get(:"@#{action}") :allow - elsif deny.instance_variable_get("@#{action}") + elsif deny.instance_variable_get(:"@#{action}") :deny end diff --git a/lib/discordrb/voice/encoder.rb b/lib/discordrb/voice/encoder.rb index 508848ae9..6e98ddb24 100644 --- a/lib/discordrb/voice/encoder.rb +++ b/lib/discordrb/voice/encoder.rb @@ -63,7 +63,7 @@ def adjust_volume(buf, mult) sample *= mult # clamp to s16 range - [32_767, [-32_768, sample].max].min + sample.clamp(-32_768, 32_767) end # After modification, make it s16le again diff --git a/spec/data/channel_spec.rb b/spec/data/channel_spec.rb index e068df8bf..656902bfb 100644 --- a/spec/data/channel_spec.rb +++ b/spec/data/channel_spec.rb @@ -19,7 +19,7 @@ shared_examples 'a Channel property' do |property_name| it 'should call #update_channel_data with data' do expect(channel).to receive(:update_channel_data).with(property_name => property_value) - channel.__send__("#{property_name}=", property_value) + channel.__send__(:"#{property_name}=", property_value) end end diff --git a/spec/overwrite_spec.rb b/spec/overwrite_spec.rb index 4362afd7e..0ced52e45 100644 --- a/spec/overwrite_spec.rb +++ b/spec/overwrite_spec.rb @@ -40,7 +40,7 @@ end it 'infers type from a User object' do - users.each do |_user_type, user| + users.each_value do |user| expect(described_class.new(user).type).to eq :member end end