From 4c919812b93e4147bd30379ededd14207af453ee Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 1 Feb 2023 11:24:22 +0100 Subject: Change number of stored items in home feed from 400 to 800 (#23349) --- app/lib/feed_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/lib/feed_manager.rb') diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index b9c5bc2cd..8d7540e0f 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -7,7 +7,7 @@ class FeedManager include Redisable # Maximum number of items stored in a single feed - MAX_ITEMS = 400 + MAX_ITEMS = 800 # Number of items in the feed since last reblog of status # before the new reblog will be inserted. Must be <= MAX_ITEMS -- cgit From 922837dc96154b0455a4cf660c3f8369c65aacb4 Mon Sep 17 00:00:00 2001 From: Jean byroot Boussier Date: Sat, 4 Mar 2023 16:38:28 +0100 Subject: Upgrade to latest redis-rb 4.x and fix deprecations (#23616) Co-authored-by: Jean Boussier --- Gemfile.lock | 2 +- app/lib/feed_manager.rb | 20 ++++++++++---------- app/models/follow_recommendation_suppression.rb | 4 ++-- app/services/batched_remove_status_service.rb | 18 +++++++++--------- .../scheduler/follow_recommendations_scheduler.rb | 13 +++++-------- config/environments/development.rb | 2 ++ config/environments/test.rb | 2 ++ config/initializers/redis.rb | 1 + db/migrate/20170920032311_fix_reblogs_in_feeds.rb | 2 +- .../20200407202420_migrate_unavailable_inboxes.rb | 5 +++-- lib/mastodon/feeds_cli.rb | 6 +----- 11 files changed, 37 insertions(+), 38 deletions(-) create mode 100644 config/initializers/redis.rb (limited to 'app/lib/feed_manager.rb') diff --git a/Gemfile.lock b/Gemfile.lock index 51cf8147b..b8b094325 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -558,7 +558,7 @@ GEM rdf-normalize (0.5.1) rdf (~> 3.2) redcarpet (3.6.0) - redis (4.5.1) + redis (4.8.1) redis-namespace (1.10.0) redis (>= 4) redlock (1.3.2) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 8d7540e0f..7dda6b185 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -273,27 +273,27 @@ class FeedManager def clean_feeds!(type, ids) reblogged_id_sets = {} - redis.pipelined do + redis.pipelined do |pipeline| ids.each do |feed_id| - redis.del(key(type, feed_id)) reblog_key = key(type, feed_id, 'reblogs') # We collect a future for this: we don't block while getting # it, but we can iterate over it later. - reblogged_id_sets[feed_id] = redis.zrange(reblog_key, 0, -1) - redis.del(reblog_key) + reblogged_id_sets[feed_id] = pipeline.zrange(reblog_key, 0, -1) + pipeline.del(key(type, feed_id), reblog_key) end end # Remove all of the reblog tracking keys we just removed the # references to. - redis.pipelined do - reblogged_id_sets.each do |feed_id, future| - future.value.each do |reblogged_id| - reblog_set_key = key(type, feed_id, "reblogs:#{reblogged_id}") - redis.del(reblog_set_key) - end + keys_to_delete = reblogged_id_sets.flat_map do |feed_id, future| + future.value.map do |reblogged_id| + key(type, feed_id, "reblogs:#{reblogged_id}") end end + + redis.del(keys_to_delete) unless keys_to_delete.empty? + + nil end private diff --git a/app/models/follow_recommendation_suppression.rb b/app/models/follow_recommendation_suppression.rb index a9dbbfc18..e261a2fe3 100644 --- a/app/models/follow_recommendation_suppression.rb +++ b/app/models/follow_recommendation_suppression.rb @@ -20,9 +20,9 @@ class FollowRecommendationSuppression < ApplicationRecord private def remove_follow_recommendations - redis.pipelined do + redis.pipelined do |pipeline| I18n.available_locales.each do |locale| - redis.zrem("follow_recommendations:#{locale}", account_id) + pipeline.zrem("follow_recommendations:#{locale}", account_id) end end end diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb index 54e5f10a4..7e9b67126 100644 --- a/app/services/batched_remove_status_service.rb +++ b/app/services/batched_remove_status_service.rb @@ -45,9 +45,9 @@ class BatchedRemoveStatusService < BaseService # Cannot be batched @status_id_cutoff = Mastodon::Snowflake.id_at(2.weeks.ago) - redis.pipelined do + redis.pipelined do |pipeline| statuses.each do |status| - unpush_from_public_timelines(status) + unpush_from_public_timelines(status, pipeline) end end end @@ -70,22 +70,22 @@ class BatchedRemoveStatusService < BaseService end end - def unpush_from_public_timelines(status) + def unpush_from_public_timelines(status, pipeline) return unless status.public_visibility? && status.id > @status_id_cutoff payload = Oj.dump(event: :delete, payload: status.id.to_s) - redis.publish('timeline:public', payload) - redis.publish(status.local? ? 'timeline:public:local' : 'timeline:public:remote', payload) + pipeline.publish('timeline:public', payload) + pipeline.publish(status.local? ? 'timeline:public:local' : 'timeline:public:remote', payload) if status.media_attachments.any? - redis.publish('timeline:public:media', payload) - redis.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload) + pipeline.publish('timeline:public:media', payload) + pipeline.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload) end status.tags.map { |tag| tag.name.mb_chars.downcase }.each do |hashtag| - redis.publish("timeline:hashtag:#{hashtag}", payload) - redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local? + pipeline.publish("timeline:hashtag:#{hashtag}", payload) + pipeline.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local? end end end diff --git a/app/workers/scheduler/follow_recommendations_scheduler.rb b/app/workers/scheduler/follow_recommendations_scheduler.rb index 04008a9d9..17cf3f2cc 100644 --- a/app/workers/scheduler/follow_recommendations_scheduler.rb +++ b/app/workers/scheduler/follow_recommendations_scheduler.rb @@ -20,7 +20,7 @@ class Scheduler::FollowRecommendationsScheduler Trends.available_locales.each do |locale| recommendations = if AccountSummary.safe.filtered.localized(locale).exists? # We can skip the work if no accounts with that language exist - FollowRecommendation.localized(locale).order(rank: :desc).limit(SET_SIZE).map { |recommendation| [recommendation.account_id, recommendation.rank] } + FollowRecommendation.localized(locale).order(rank: :desc).limit(SET_SIZE).map { |recommendation| [recommendation.rank, recommendation.account_id] } else [] end @@ -33,14 +33,14 @@ class Scheduler::FollowRecommendationsScheduler # Language-specific results should be above language-agnostic ones, # otherwise language-agnostic ones will always overshadow them - recommendations.map! { |(account_id, rank)| [account_id, rank + max_fallback_rank] } + recommendations.map! { |(rank, account_id)| [rank + max_fallback_rank, account_id] } added = 0 fallback_recommendations.each do |recommendation| - next if recommendations.any? { |(account_id, _)| account_id == recommendation.account_id } + next if recommendations.any? { |(_, account_id)| account_id == recommendation.account_id } - recommendations << [recommendation.account_id, recommendation.rank] + recommendations << [recommendation.rank, recommendation.account_id] added += 1 break if added >= missing @@ -49,10 +49,7 @@ class Scheduler::FollowRecommendationsScheduler redis.multi do |multi| multi.del(key(locale)) - - recommendations.each do |(account_id, rank)| - multi.zadd(key(locale), rank, account_id) - end + multi.zadd(key(locale), recommendations) end end end diff --git a/config/environments/development.rb b/config/environments/development.rb index de8762ff7..29b17a350 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -87,6 +87,8 @@ Rails.application.configure do config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109') end +Redis.raise_deprecations = true + ActiveRecordQueryTrace.enabled = ENV['QUERY_TRACE_ENABLED'] == 'true' module PrivateAddressCheck diff --git a/config/environments/test.rb b/config/environments/test.rb index ef3cb2e48..9cbf31e8d 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -73,3 +73,5 @@ end # Catch serialization warnings early Sidekiq.strict_args! + +Redis.raise_deprecations = true diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb new file mode 100644 index 000000000..f2bbd1e45 --- /dev/null +++ b/config/initializers/redis.rb @@ -0,0 +1 @@ +Redis.sadd_returns_boolean = false diff --git a/db/migrate/20170920032311_fix_reblogs_in_feeds.rb b/db/migrate/20170920032311_fix_reblogs_in_feeds.rb index 4ab68e8f3..7e2db0ff3 100644 --- a/db/migrate/20170920032311_fix_reblogs_in_feeds.rb +++ b/db/migrate/20170920032311_fix_reblogs_in_feeds.rb @@ -1,6 +1,6 @@ class FixReblogsInFeeds < ActiveRecord::Migration[5.1] def up - redis = Redis.current + redis = RedisConfiguration.pool.checkout fm = FeedManager.instance # Old scheme: diff --git a/db/migrate/20200407202420_migrate_unavailable_inboxes.rb b/db/migrate/20200407202420_migrate_unavailable_inboxes.rb index 92a3acb5d..8f9c68794 100644 --- a/db/migrate/20200407202420_migrate_unavailable_inboxes.rb +++ b/db/migrate/20200407202420_migrate_unavailable_inboxes.rb @@ -2,7 +2,8 @@ class MigrateUnavailableInboxes < ActiveRecord::Migration[5.2] disable_ddl_transaction! def up - urls = Redis.current.smembers('unavailable_inboxes') + redis = RedisConfiguration.pool.checkout + urls = redis.smembers('unavailable_inboxes') hosts = urls.map do |url| Addressable::URI.parse(url).normalized_host @@ -14,7 +15,7 @@ class MigrateUnavailableInboxes < ActiveRecord::Migration[5.2] UnavailableDomain.create(domain: host) end - Redis.current.del(*(['unavailable_inboxes'] + Redis.current.keys('exhausted_deliveries:*'))) + redis.del(*(['unavailable_inboxes'] + redis.keys('exhausted_deliveries:*'))) end def down; end diff --git a/lib/mastodon/feeds_cli.rb b/lib/mastodon/feeds_cli.rb index 428d63a44..fcfb48740 100644 --- a/lib/mastodon/feeds_cli.rb +++ b/lib/mastodon/feeds_cli.rb @@ -53,11 +53,7 @@ module Mastodon desc 'clear', 'Remove all home and list feeds from Redis' def clear keys = redis.keys('feed:*') - - redis.pipelined do - keys.each { |key| redis.del(key) } - end - + redis.del(keys) say('OK', :green) end end -- cgit From ff168ef2024626f37fa776fde5739dcd58ecb9f2 Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 9 Apr 2023 11:25:30 +0200 Subject: Fix most rubocop issues (#2165) * Run rubocop --autocorrect on app/, config/ and lib/, also manually fix some remaining style issues * Run rubocop --autocorrect-all on db/ * Run rubocop --autocorrect-all on `spec/` and fix remaining issues --- .rubocop_todo.yml | 2 + .../api/v1/timelines/public_controller.rb | 2 +- app/controllers/auth/confirmations_controller.rb | 13 ++-- app/controllers/settings/flavours_controller.rb | 4 +- app/helpers/accounts_helper.rb | 2 +- app/lib/advanced_text_formatter.rb | 1 + app/lib/feed_manager.rb | 2 + app/lib/themes.rb | 45 ++++++------ app/models/direct_feed.rb | 9 +-- app/models/status.rb | 19 ++--- app/models/user.rb | 1 - app/serializers/activitypub/note_serializer.rb | 1 + app/serializers/rest/account_serializer.rb | 2 +- app/serializers/rest/mute_serializer.rb | 4 +- app/serializers/rest/status_serializer.rb | 4 +- app/services/backup_service.rb | 2 +- app/services/fan_out_on_write_service.rb | 2 +- app/services/post_status_service.rb | 25 ++++--- app/validators/status_pin_validator.rb | 2 +- config/initializers/0_duplicate_migrations.rb | 24 ++++--- config/initializers/simple_form.rb | 1 + db/migrate/20171009222537_create_keyword_mutes.rb | 2 + ...900_move_keyword_mutes_into_glitch_namespace.rb | 2 + ...171210213213_add_local_only_flag_to_statuses.rb | 2 + db/migrate/20180410220657_create_bookmarks.rb | 2 + ..._add_apply_to_mentions_flag_to_keyword_mutes.rb | 2 + db/migrate/20180707193142_migrate_filters.rb | 12 ++-- .../20190512200918_add_content_type_to_statuses.rb | 2 + ...20209175231_add_content_type_to_status_edits.rb | 2 + .../20180813160548_post_migrate_filters.rb | 6 +- lib/sanitize_ext/sanitize_config.rb | 8 +-- lib/tasks/assets.rake | 12 ++-- lib/tasks/glitchsoc.rake | 8 ++- .../api/v1/accounts/credentials_controller_spec.rb | 4 +- .../api/v1/timelines/direct_controller_spec.rb | 2 +- spec/controllers/application_controller_spec.rb | 4 +- .../settings/flavours_controller_spec.rb | 3 +- spec/lib/advanced_text_formatter_spec.rb | 82 +++++++++++----------- spec/models/concerns/account_interactions_spec.rb | 39 +--------- spec/models/public_feed_spec.rb | 12 ++-- spec/models/status_spec.rb | 42 +++++------ spec/models/tag_feed_spec.rb | 2 +- spec/policies/status_policy_spec.rb | 4 +- spec/services/notify_service_spec.rb | 2 +- spec/validators/status_length_validator_spec.rb | 2 +- 45 files changed, 210 insertions(+), 215 deletions(-) (limited to 'app/lib/feed_manager.rb') diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 2e4801a55..dc7e21dc5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -473,6 +473,7 @@ RSpec/ContextWording: - 'spec/lib/activitypub/activity/create_spec.rb' - 'spec/lib/activitypub/activity/follow_spec.rb' - 'spec/lib/activitypub/activity/reject_spec.rb' + - 'spec/lib/advanced_text_formatter_spec.rb' - 'spec/lib/emoji_formatter_spec.rb' - 'spec/lib/entity_cache_spec.rb' - 'spec/lib/feed_manager_spec.rb' @@ -1321,6 +1322,7 @@ Rails/FilePath: - 'app/models/setting.rb' - 'app/validators/reaction_validator.rb' - 'config/environments/test.rb' + - 'config/initializers/locale.rb' - 'db/migrate/20170716191202_add_hide_notifications_to_mute.rb' - 'db/migrate/20171005171936_add_disabled_to_custom_emojis.rb' - 'db/migrate/20171028221157_add_reblogs_to_follows.rb' diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index 493fe4776..4675af921 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -40,7 +40,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController only_media: truthy_param?(:only_media), allow_local_only: truthy_param?(:allow_local_only), with_replies: Setting.show_replies_in_public_timelines, - with_reblogs: Setting.show_reblogs_in_public_timelines, + with_reblogs: Setting.show_reblogs_in_public_timelines ) end diff --git a/app/controllers/auth/confirmations_controller.rb b/app/controllers/auth/confirmations_controller.rb index 0817a905c..620fb621d 100644 --- a/app/controllers/auth/confirmations_controller.rb +++ b/app/controllers/auth/confirmations_controller.rb @@ -15,12 +15,6 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController skip_before_action :require_functional! - def new - super - - resource.email = current_user.unconfirmed_email || current_user.email if user_signed_in? - end - def show old_session_values = session.to_hash reset_session @@ -29,6 +23,12 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController super end + def new + super + + resource.email = current_user.unconfirmed_email || current_user.email if user_signed_in? + end + def confirm_captcha check_captcha! do |message| flash.now[:alert] = message @@ -51,6 +51,7 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController # step. confirmation_token = params[:confirmation_token] return if confirmation_token.nil? + @confirmation_user = User.find_first_by_auth_conditions(confirmation_token: confirmation_token) end diff --git a/app/controllers/settings/flavours_controller.rb b/app/controllers/settings/flavours_controller.rb index c1172598b..b179b9429 100644 --- a/app/controllers/settings/flavours_controller.rb +++ b/app/controllers/settings/flavours_controller.rb @@ -12,9 +12,7 @@ class Settings::FlavoursController < Settings::BaseController end def show - unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour) - redirect_to action: 'show', flavour: current_flavour - end + redirect_to action: 'show', flavour: current_flavour unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour) @listing = Themes.instance.flavours @selected = params[:flavour] diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 91c3a116b..b8277ee17 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -28,7 +28,7 @@ module AccountsHelper end def hide_followers_count?(account) - Setting.hide_followers_count || account.user&.settings['hide_followers_count'] + Setting.hide_followers_count || account.user&.settings&.[]('hide_followers_count') end def account_description(account) diff --git a/app/lib/advanced_text_formatter.rb b/app/lib/advanced_text_formatter.rb index 21e81d4d1..cdf1e2d9c 100644 --- a/app/lib/advanced_text_formatter.rb +++ b/app/lib/advanced_text_formatter.rb @@ -15,6 +15,7 @@ class AdvancedTextFormatter < TextFormatter def autolink(link, link_type) return link if link_type == :email + @format_link.call(link) end end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 4ce888fc9..15ff6d15f 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -306,6 +306,7 @@ class FeedManager statuses.each do |status| next if filter_from_direct?(status, account) + added += 1 if add_to_feed(:direct, account.id, status) end @@ -459,6 +460,7 @@ class FeedManager # @return [Boolean] def filter_from_direct?(status, receiver_id) return false if receiver_id == status.account_id + filter_from_mentions?(status, receiver_id) end diff --git a/app/lib/themes.rb b/app/lib/themes.rb index 81e016d4a..45ba47780 100644 --- a/app/lib/themes.rb +++ b/app/lib/themes.rb @@ -7,24 +7,23 @@ class Themes include Singleton def initialize - core = YAML.load_file(Rails.root.join('app', 'javascript', 'core', 'theme.yml')) - core['pack'] = Hash.new unless core['pack'] + core['pack'] = {} unless core['pack'] - result = Hash.new - Dir.glob(Rails.root.join('app', 'javascript', 'flavours', '*', 'theme.yml')) do |path| - data = YAML.load_file(path) + result = {} + Rails.root.glob('app/javascript/flavours/*/theme.yml') do |pathname| + data = YAML.load_file(pathname) next unless data['pack'] - dir = File.dirname(path) - name = File.basename(dir) + dir = pathname.dirname + name = dir.basename.to_s locales = [] screenshots = [] if data['locales'] Dir.glob(File.join(dir, data['locales'], '*.{js,json}')) do |locale| - localeName = File.basename(locale, File.extname(locale)) - locales.push(localeName) unless localeName.match(/defaultMessages|whitelist|index/) + locale_name = File.basename(locale, File.extname(locale)) + locales.push(locale_name) unless /defaultMessages|whitelist|index/.match?(locale_name) end end @@ -43,34 +42,30 @@ class Themes result[name] = data end - Dir.glob(Rails.root.join('app', 'javascript', 'skins', '*', '*')) do |path| - ext = File.extname(path) - skin = File.basename(path) - name = File.basename(File.dirname(path)) + Rails.root.glob('app/javascript/skins/*/*') do |pathname| + ext = pathname.extname.to_s + skin = pathname.basename.to_s + name = pathname.dirname.basename.to_s next unless result[name] - if File.directory?(path) + if pathname.directory? pack = [] - Dir.glob(File.join(path, '*.{css,scss}')) do |sheet| - pack.push(File.basename(sheet, File.extname(sheet))) + pathname.glob('*.{css,scss}') do |sheet| + pack.push(sheet.basename(sheet.extname).to_s) end - elsif ext.match(/^\.s?css$/i) - skin = File.basename(path, ext) + elsif /^\.s?css$/i.match?(ext) + skin = pathname.basename(ext).to_s pack = ['common'] end - if skin != 'default' - result[name]['skin'][skin] = pack - end + result[name]['skin'][skin] = pack if skin != 'default' end @core = core @conf = result end - def core - @core - end + attr_reader :core def flavour(name) @conf[name] @@ -86,7 +81,7 @@ class Themes def flavours_and_skins flavours.map do |flavour| - [flavour, skins_for(flavour).map{ |skin| [flavour, skin] }] + [flavour, skins_for(flavour).map { |skin| [flavour, skin] }] end end end diff --git a/app/models/direct_feed.rb b/app/models/direct_feed.rb index 1f2448070..689a735b3 100644 --- a/app/models/direct_feed.rb +++ b/app/models/direct_feed.rb @@ -4,9 +4,8 @@ class DirectFeed < Feed include Redisable def initialize(account) - @type = :direct - @id = account.id @account = account + super(:direct, account.id) end def get(limit, max_id = nil, since_id = nil, min_id = nil) @@ -19,10 +18,12 @@ class DirectFeed < Feed private - def from_database(limit, max_id, since_id, min_id) + # TODO: _min_id is not actually handled by `as_direct_timeline` + def from_database(limit, max_id, since_id, _min_id) loop do - statuses = Status.as_direct_timeline(@account, limit, max_id, since_id, min_id) + statuses = Status.as_direct_timeline(@account, limit, max_id, since_id) return statuses if statuses.empty? + max_id = statuses.last.id statuses = statuses.reject { |status| FeedManager.instance.filter?(:direct, status, @account) } return statuses unless statuses.empty? diff --git a/app/models/status.rb b/app/models/status.rb index e01ddb5c5..8a58e5d68 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -338,7 +338,7 @@ class Status < ApplicationRecord visibilities.keys - %w(direct limited) end - def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil, cache_ids = false) + def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil) # direct timeline is mix of direct message from_me and to_me. # 2 queries are executed with pagination. # constant expression using arel_table is required for partial index @@ -369,14 +369,9 @@ class Status < ApplicationRecord query_to_me = query_to_me.where('mentions.status_id > ?', since_id) end - if cache_ids - # returns array of cache_ids object that have id and updated_at - (query_from_me.cache_ids.to_a + query_to_me.cache_ids.to_a).uniq(&:id).sort_by(&:id).reverse.take(limit) - else - # returns ActiveRecord.Relation - items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit) - Status.where(id: items.map(&:id)) - end + # returns ActiveRecord.Relation + items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit) + Status.where(id: items.map(&:id)) end def favourites_map(status_ids, account_id) @@ -553,9 +548,9 @@ class Status < ApplicationRecord end def set_locality - if account.domain.nil? && !attribute_changed?(:local_only) - self.local_only = marked_local_only? - end + return unless account.domain.nil? && !attribute_changed?(:local_only) + + self.local_only = marked_local_only? end def set_conversation diff --git a/app/models/user.rb b/app/models/user.rb index 3471bb2c1..daf8768e8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -244,7 +244,6 @@ class User < ApplicationRecord end def functional? - functional_or_moved? end diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb index ca067ed9b..52ffaf717 100644 --- a/app/serializers/activitypub/note_serializer.rb +++ b/app/serializers/activitypub/note_serializer.rb @@ -32,6 +32,7 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer def id raise Mastodon::NotPermittedError, 'Local-only statuses should not be serialized' if object.local_only? && !instance_options[:allow_local_only] + ActivityPub::TagManager.instance.uri_for(object) end diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index e6c8fe4b2..d4e7ac974 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -91,7 +91,7 @@ class REST::AccountSerializer < ActiveModel::Serializer end def followers_count - (Setting.hide_followers_count || object.user&.setting_hide_followers_count) ? -1 : object.followers_count + Setting.hide_followers_count || object.user&.setting_hide_followers_count ? -1 : object.followers_count end def display_name diff --git a/app/serializers/rest/mute_serializer.rb b/app/serializers/rest/mute_serializer.rb index 043a2f059..c9b55ff16 100644 --- a/app/serializers/rest/mute_serializer.rb +++ b/app/serializers/rest/mute_serializer.rb @@ -2,7 +2,7 @@ class REST::MuteSerializer < ActiveModel::Serializer include RoutingHelper - + attributes :id, :account, :target_account, :created_at, :hide_notifications def account @@ -12,4 +12,4 @@ class REST::MuteSerializer < ActiveModel::Serializer def target_account REST::AccountSerializer.new(object.target_account) end -end \ No newline at end of file +end diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index 659c45b83..eb5f3c3ea 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -13,7 +13,7 @@ class REST::StatusSerializer < ActiveModel::Serializer attribute :muted, if: :current_user? attribute :bookmarked, if: :current_user? attribute :pinned, if: :pinnable? - attribute :local_only if :local? + attribute :local_only, if: :local? has_many :filtered, serializer: REST::FilterResultSerializer, if: :current_user? attribute :content, unless: :source_requested? @@ -32,6 +32,8 @@ class REST::StatusSerializer < ActiveModel::Serializer has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer + delegate :local?, to: :object + def id object.id.to_s end diff --git a/app/services/backup_service.rb b/app/services/backup_service.rb index a9d740211..c5e7a8e58 100644 --- a/app/services/backup_service.rb +++ b/app/services/backup_service.rb @@ -154,7 +154,7 @@ class BackupService < BaseService object, serializer: serializer, adapter: ActivityPub::Adapter, - allow_local_only: true, + allow_local_only: true ).as_json end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 8e74e152e..3b14a6748 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -116,7 +116,7 @@ class FanOutOnWriteService < BaseService end def deliver_to_direct_timelines! - FeedInsertWorker.push_bulk(@status.mentions.includes(:account).map(&:account).select { |mentioned_account| mentioned_account.local? }) do |account| + FeedInsertWorker.push_bulk(@status.mentions.includes(:account).map(&:account).select(&:local?)) do |account| [@status.id, account.id, 'direct', { 'update' => update? }] end end diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index bca3b3ff7..74ec47a33 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -61,17 +61,22 @@ class PostStatusService < BaseService private - def preprocess_attributes! - if @text.blank? && @options[:spoiler_text].present? - @text = '.' - if @media&.find(&:video?) || @media&.find(&:gifv?) - @text = '📹' - elsif @media&.find(&:audio?) - @text = '🎵' - elsif @media&.find(&:image?) - @text = '🖼' - end + def fill_blank_text! + return unless @text.blank? && @options[:spoiler_text].present? + + if @media&.any?(&:video?) || @media&.any?(&:gifv?) + @text = '📹' + elsif @media&.any?(&:audio?) + @text = '🎵' + elsif @media&.any?(&:image?) + @text = '🖼' + else + @text = '.' end + end + + def preprocess_attributes! + fill_blank_text! @sensitive = (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present? @visibility = @options[:visibility] || @account.user&.setting_default_privacy @visibility = :unlisted if @visibility&.to_sym == :public && @account.silenced? diff --git a/app/validators/status_pin_validator.rb b/app/validators/status_pin_validator.rb index 9466a81fe..4af7bd295 100644 --- a/app/validators/status_pin_validator.rb +++ b/app/validators/status_pin_validator.rb @@ -7,6 +7,6 @@ class StatusPinValidator < ActiveModel::Validator pin.errors.add(:base, I18n.t('statuses.pin_errors.reblog')) if pin.status.reblog? pin.errors.add(:base, I18n.t('statuses.pin_errors.ownership')) if pin.account_id != pin.status.account_id pin.errors.add(:base, I18n.t('statuses.pin_errors.direct')) if pin.status.direct_visibility? - pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count >= MAX_PINNED && pin.account.local? + pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count >= MAX_PINNED && pin.account.local? end end diff --git a/config/initializers/0_duplicate_migrations.rb b/config/initializers/0_duplicate_migrations.rb index 6c45e4bd2..1b8b59025 100644 --- a/config/initializers/0_duplicate_migrations.rb +++ b/config/initializers/0_duplicate_migrations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Some migrations have been present in glitch-soc for a long time and have then # been merged in upstream Mastodon, under a different version number. # @@ -12,24 +14,26 @@ # we decided monkey-patching Rails' Migrator to completely ignore the duplicate, # keeping only the one that has run, or an arbitrary one. -ALLOWED_DUPLICATES = [20180410220657, 20180831171112].freeze +ALLOWED_DUPLICATES = [2018_04_10_220657, 2018_08_31_171112].freeze module ActiveRecord class Migrator def self.new(direction, migrations, schema_migration, target_version = nil) migrated = Set.new(Base.connection.migration_context.get_all_versions) - migrations.group_by(&:name).each do |name, duplicates| - if duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) } - # We have a set of allowed duplicates. Keep the migrated one, if any. - non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) } + migrations.group_by(&:name).each do |_name, duplicates| + next unless duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) } + + # We have a set of allowed duplicates. Keep the migrated one, if any. + non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) } - if duplicates.length == non_migrated.length || non_migrated.length == 0 + migrations = begin + if duplicates.length == non_migrated.length || non_migrated.empty? # There weren't any migrated one, so we have to pick one “canonical” migration - migrations = migrations - duplicates[1..-1] + migrations - duplicates[1..] else # Just reject every duplicate which hasn't been migrated yet - migrations = migrations - non_migrated + migrations - non_migrated end end end @@ -43,10 +47,10 @@ module ActiveRecord # A set of duplicated migrations is considered migrated if at least one of # them is migrated. migrated = get_all_versions - migrations.group_by(&:name).each do |name, duplicates| + migrations.group_by(&:name).each do |_name, duplicates| return true unless duplicates.any? { |m| migrated.include?(m.version.to_i) } end - return false + false end end end diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb index d167a1600..fff4f538e 100644 --- a/config/initializers/simple_form.rb +++ b/config/initializers/simple_form.rb @@ -22,6 +22,7 @@ end module GlitchOnlyComponent def glitch_only(_wrapper_options = nil) return unless options[:glitch_only] + options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.glitch_only'), class: 'glitch_only')]) } nil end diff --git a/db/migrate/20171009222537_create_keyword_mutes.rb b/db/migrate/20171009222537_create_keyword_mutes.rb index 66411ba1d..77c88b0a5 100644 --- a/db/migrate/20171009222537_create_keyword_mutes.rb +++ b/db/migrate/20171009222537_create_keyword_mutes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateKeywordMutes < ActiveRecord::Migration[5.1] def change create_table :keyword_mutes do |t| diff --git a/db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb b/db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb index 269bb49d6..b6ea537c2 100644 --- a/db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb +++ b/db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MoveKeywordMutesIntoGlitchNamespace < ActiveRecord::Migration[5.1] def change safety_assured do diff --git a/db/migrate/20171210213213_add_local_only_flag_to_statuses.rb b/db/migrate/20171210213213_add_local_only_flag_to_statuses.rb index af1e29d6a..010503b10 100644 --- a/db/migrate/20171210213213_add_local_only_flag_to_statuses.rb +++ b/db/migrate/20171210213213_add_local_only_flag_to_statuses.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddLocalOnlyFlagToStatuses < ActiveRecord::Migration[5.1] def change add_column :statuses, :local_only, :boolean diff --git a/db/migrate/20180410220657_create_bookmarks.rb b/db/migrate/20180410220657_create_bookmarks.rb index bc79022e4..aba21f5ea 100644 --- a/db/migrate/20180410220657_create_bookmarks.rb +++ b/db/migrate/20180410220657_create_bookmarks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration is a duplicate of 20180831171112 and may get ignored, see # config/initializers/0_duplicate_migrations.rb diff --git a/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb b/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb index cd97d0f20..8078a07bf 100644 --- a/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb +++ b/db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'mastodon/migration_helpers' class AddApplyToMentionsFlagToKeywordMutes < ActiveRecord::Migration[5.2] diff --git a/db/migrate/20180707193142_migrate_filters.rb b/db/migrate/20180707193142_migrate_filters.rb index 067c53357..8f6b3e1bb 100644 --- a/db/migrate/20180707193142_migrate_filters.rb +++ b/db/migrate/20180707193142_migrate_filters.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class MigrateFilters < ActiveRecord::Migration[5.2] class GlitchKeywordMute < ApplicationRecord # Dummy class, as we removed Glitch::KeywordMute - belongs_to :account, required: true + belongs_to :account, optional: false validates_presence_of :keyword end @@ -15,7 +17,7 @@ class MigrateFilters < ActiveRecord::Migration[5.2] private def clean_up_contexts - self.context = Array(context).map(&:strip).map(&:presence).compact + self.context = Array(context).map(&:strip).filter_map(&:presence) end end @@ -27,7 +29,8 @@ class MigrateFilters < ActiveRecord::Migration[5.2] phrase: filter.keyword, context: filter.apply_to_mentions ? %w(home public notifications) : %w(home public), whole_word: filter.whole_word, - irreversible: true) + irreversible: true + ) end end @@ -48,7 +51,8 @@ class MigrateFilters < ActiveRecord::Migration[5.2] GlitchKeywordMute.where(account: filter.account).create!( keyword: filter.phrase, whole_word: filter.whole_word, - apply_to_mentions: filter.context.include?('notifications')) + apply_to_mentions: filter.context.include?('notifications') + ) end end end diff --git a/db/migrate/20190512200918_add_content_type_to_statuses.rb b/db/migrate/20190512200918_add_content_type_to_statuses.rb index efbe2caa7..31c1a4f17 100644 --- a/db/migrate/20190512200918_add_content_type_to_statuses.rb +++ b/db/migrate/20190512200918_add_content_type_to_statuses.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddContentTypeToStatuses < ActiveRecord::Migration[5.2] def change add_column :statuses, :content_type, :string diff --git a/db/migrate/20220209175231_add_content_type_to_status_edits.rb b/db/migrate/20220209175231_add_content_type_to_status_edits.rb index 0e4e52fcb..bb414535d 100644 --- a/db/migrate/20220209175231_add_content_type_to_status_edits.rb +++ b/db/migrate/20220209175231_add_content_type_to_status_edits.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddContentTypeToStatusEdits < ActiveRecord::Migration[6.1] def change add_column :status_edits, :content_type, :string diff --git a/db/post_migrate/20180813160548_post_migrate_filters.rb b/db/post_migrate/20180813160548_post_migrate_filters.rb index 588548c1d..82acf13d5 100644 --- a/db/post_migrate/20180813160548_post_migrate_filters.rb +++ b/db/post_migrate/20180813160548_post_migrate_filters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PostMigrateFilters < ActiveRecord::Migration[5.2] disable_ddl_transaction! @@ -5,7 +7,5 @@ class PostMigrateFilters < ActiveRecord::Migration[5.2] drop_table :glitch_keyword_mutes if table_exists? :glitch_keyword_mutes end - def down - end + def down; end end - diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index dfc586561..4c0e9b858 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -48,9 +48,9 @@ class Sanitize node.content = "[🖼 #{node['alt']}]" else url = node['href'] - prefix = url.match(/\Ahttps?:\/\/(www\.)?/).to_s + prefix = url.match(%r{\Ahttps?://(www\.)?}).to_s text = url[prefix.length, 30] - text = text + "…" if url[prefix.length..-1].length > 30 + text += '…' if url.length - prefix.length > 30 node.content = "[🖼 #{text}]" end end @@ -88,7 +88,7 @@ class Sanitize }, protocols: { - 'a' => { 'href' => LINK_PROTOCOLS }, + 'a' => { 'href' => LINK_PROTOCOLS }, 'blockquote' => { 'cite' => LINK_PROTOCOLS }, }, @@ -126,7 +126,7 @@ class Sanitize node = env[:node] - rel = (node['rel'] || '').split(' ') & ['tag'] + rel = (node['rel'] || '').split & ['tag'] rel += ['nofollow', 'noopener', 'noreferrer'] unless TagManager.instance.local_url?(node['href']) if rel.empty? diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index e1102af33..76e190f70 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -3,14 +3,14 @@ namespace :assets do desc 'Generate static pages' task generate_static_pages: :environment do - class StaticApplicationController < ApplicationController - def current_user - nil + def render_static_page(action, dest:, **opts) + renderer = Class.new(ApplicationController) do + def current_user + nil + end end - end - def render_static_page(action, dest:, **opts) - html = StaticApplicationController.render(action, opts) + html = renderer.render(action, opts) File.write(dest, html) end diff --git a/lib/tasks/glitchsoc.rake b/lib/tasks/glitchsoc.rake index 79e864648..72558fa19 100644 --- a/lib/tasks/glitchsoc.rake +++ b/lib/tasks/glitchsoc.rake @@ -1,8 +1,12 @@ +# frozen_string_literal: true + namespace :glitchsoc do desc 'Backfill local-only flag on statuses table' task backfill_local_only: :environment do - Status.local.where(local_only: nil).find_each do |st| - ActiveRecord::Base.logger.silence { st.update_attribute(:local_only, st.marked_local_only?) } + Status.local.where(local_only: nil).find_each do |status| + ActiveRecord::Base.logger.silence do + status.update_attribute(:local_only, status.marked_local_only?) # rubocop:disable Rails/SkipsModelValidations + end end end end diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb index de08dd524..a677aaad0 100644 --- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb @@ -75,10 +75,10 @@ describe Api::V1::Accounts::CredentialsController do end end - describe 'with invalid data' do + describe 'with a too long profile bio' do before do note = 'This is too long. ' - note = note + 'a' * (Account::MAX_NOTE_LENGTH - note.length + 1) + note += 'a' * (Account::MAX_NOTE_LENGTH - note.length + 1) patch :update, params: { note: note } end diff --git a/spec/controllers/api/v1/timelines/direct_controller_spec.rb b/spec/controllers/api/v1/timelines/direct_controller_spec.rb index a22c2cbea..def67a0fe 100644 --- a/spec/controllers/api/v1/timelines/direct_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/direct_controller_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe Api::V1::Timelines::DirectController, type: :controller do +RSpec.describe Api::V1::Timelines::DirectController do let(:user) { Fabricate(:user) } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') } diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 1aabae0ea..82455d874 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -75,8 +75,8 @@ describe ApplicationController, type: :controller do describe 'helper_method :current_flavour' do it 'returns "glitch" when theme wasn\'t changed in admin settings' do - allow(Setting).to receive(:default_settings).and_return({'skin' => 'default'}) - allow(Setting).to receive(:default_settings).and_return({'flavour' => 'glitch'}) + allow(Setting).to receive(:default_settings).and_return({ 'skin' => 'default' }) + allow(Setting).to receive(:default_settings).and_return({ 'flavour' => 'glitch' }) expect(controller.view_context.current_flavour).to eq 'glitch' end diff --git a/spec/controllers/settings/flavours_controller_spec.rb b/spec/controllers/settings/flavours_controller_spec.rb index f89bde1f9..8c7d4a768 100644 --- a/spec/controllers/settings/flavours_controller_spec.rb +++ b/spec/controllers/settings/flavours_controller_spec.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true + require 'rails_helper' -RSpec.describe Settings::FlavoursController, type: :controller do +RSpec.describe Settings::FlavoursController do let(:user) { Fabricate(:user) } before do diff --git a/spec/lib/advanced_text_formatter_spec.rb b/spec/lib/advanced_text_formatter_spec.rb index c1e469606..8b27b56a1 100644 --- a/spec/lib/advanced_text_formatter_spec.rb +++ b/spec/lib/advanced_text_formatter_spec.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe AdvancedTextFormatter do describe '#to_s' do + subject { described_class.new(text, preloaded_accounts: preloaded_accounts, content_type: content_type).to_s } + let(:preloaded_accounts) { nil } let(:content_type) { 'text/markdown' } - subject { described_class.new(text, preloaded_accounts: preloaded_accounts, content_type: content_type).to_s } - context 'given a markdown source' do let(:content_type) { 'text/markdown' } @@ -14,7 +16,7 @@ RSpec.describe AdvancedTextFormatter do let(:text) { 'text' } it 'paragraphizes the text' do - is_expected.to eq '

text

' + expect(subject).to eq '

text

' end end @@ -22,7 +24,7 @@ RSpec.describe AdvancedTextFormatter do let(:text) { "line\nfeed" } it 'removes line feeds' do - is_expected.not_to include "\n" + expect(subject).to_not include "\n" end end @@ -30,7 +32,7 @@ RSpec.describe AdvancedTextFormatter do let(:text) { 'test `foo` bar' } it 'formats code using ' do - is_expected.to include 'test foo bar' + expect(subject).to include 'test foo bar' end end @@ -38,15 +40,15 @@ RSpec.describe AdvancedTextFormatter do let(:text) { "test\n\n```\nint main(void) {\n return 0; // https://joinmastodon.org/foo\n}\n```\n" } it 'formats code using
 and ' do
-          is_expected.to include '
int main'
+          expect(subject).to include '
int main'
         end
 
         it 'does not strip leading spaces' do
-          is_expected.to include '>  return 0'
+          expect(subject).to include '>  return 0'
         end
 
         it 'does not format links' do
-          is_expected.to include 'return 0; // https://joinmastodon.org/foo'
+          expect(subject).to include 'return 0; // https://joinmastodon.org/foo'
         end
       end
 
@@ -54,7 +56,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'test `https://foo.bar/bar` bar' }
 
         it 'does not rewrite the link' do
-          is_expected.to include 'test https://foo.bar/bar bar'
+          expect(subject).to include 'test https://foo.bar/bar bar'
         end
       end
 
@@ -62,7 +64,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'foo https://cb6e6126.ngrok.io/about/more' }
 
         it 'creates a link' do
-          is_expected.to include '@alice'
+          expect(subject).to include '@alice'
         end
       end
 
@@ -80,7 +82,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { '@alice' }
 
         it 'does not create a mention link' do
-          is_expected.to include '@alice'
+          expect(subject).to include '@alice'
         end
       end
 
@@ -88,7 +90,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"'
+          expect(subject).to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"'
         end
       end
 
@@ -96,7 +98,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'http://google.com' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="http://google.com"'
+          expect(subject).to include 'href="http://google.com"'
         end
       end
 
@@ -104,7 +106,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'http://example.gay' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="http://example.gay"'
+          expect(subject).to include 'href="http://example.gay"'
         end
       end
 
@@ -112,11 +114,11 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://nic.みんな/' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="https://nic.みんな/"'
+          expect(subject).to include 'href="https://nic.みんな/"'
         end
 
         it 'has display URL' do
-          is_expected.to include 'nic.みんな/'
+          expect(subject).to include 'nic.みんな/'
         end
       end
 
@@ -124,7 +126,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' }
 
         it 'matches the full URL but not the period' do
-          is_expected.to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"'
+          expect(subject).to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"'
         end
       end
 
@@ -132,7 +134,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { '(http://google.com/)' }
 
         it 'matches the full URL but not the parentheses' do
-          is_expected.to include 'href="http://google.com/"'
+          expect(subject).to include 'href="http://google.com/"'
         end
       end
 
@@ -140,7 +142,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'http://www.google.com!' }
 
         it 'matches the full URL but not the exclamation point' do
-          is_expected.to include 'href="http://www.google.com"'
+          expect(subject).to include 'href="http://www.google.com"'
         end
       end
 
@@ -148,7 +150,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { "http://www.google.com'" }
 
         it 'matches the full URL but not the single quote' do
-          is_expected.to include 'href="http://www.google.com"'
+          expect(subject).to include 'href="http://www.google.com"'
         end
       end
     end
@@ -157,7 +159,7 @@ RSpec.describe AdvancedTextFormatter do
       let(:text) { 'http://www.google.com>' }
 
       it 'matches the full URL but not the angle bracket' do
-        is_expected.to include 'href="http://www.google.com"'
+        expect(subject).to include 'href="http://www.google.com"'
       end
     end
 
@@ -166,7 +168,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"'
+          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"'
         end
       end
 
@@ -174,7 +176,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"'
+          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"'
         end
       end
 
@@ -182,7 +184,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"'
+          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"'
         end
       end
 
@@ -190,7 +192,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' }
 
         it 'preserves escaped unicode characters' do
-          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"'
+          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"'
         end
       end
 
@@ -198,7 +200,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' }
 
         it 'matches the full URL' do
-          is_expected.to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"'
+          expect(subject).to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"'
         end
       end
 
@@ -206,7 +208,7 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { '"https://example.com/"' }
 
         it 'does not match the quotation marks' do
-          is_expected.to include 'href="https://example.com/"'
+          expect(subject).to include 'href="https://example.com/"'
         end
       end
 
@@ -214,19 +216,19 @@ RSpec.describe AdvancedTextFormatter do
         let(:text) { '' }
 
         it 'does not match the angle brackets' do
-          is_expected.to include 'href="https://example.com/"'
+          expect(subject).to include 'href="https://example.com/"'
         end
       end
 
       context 'given a URL containing unsafe code (XSS attack, invisible part)' do
-        let(:text) { %q{http://example.com/blahblahblahblah/a} }
+        let(:text) { 'http://example.com/blahblahblahblah/a' }
 
         it 'does not include the HTML in the URL' do
-          is_expected.to include '"http://example.com/blahblahblahblah/a"'
+          expect(subject).to include '"http://example.com/blahblahblahblah/a"'
         end
 
         it 'does not include a script tag' do
-          is_expected.to_not include '' }
 
         it 'does not include a script tag' do
-          is_expected.to_not include '