Mastodonのコードを読んでみることにしました。
知らないgemが一杯あったのでまずは調べてみることにしました。標準添付ライブラリ、Railsにデフォルトで含まれているものは除きます。また、group :development
とか、group指定ありのは疲れたのでまた今度。
実際のコードに目を通しながら調べましたが、勘違いなどあればご指摘頂けるとうれしいです。
hamlit-rails
hamlit-rails provides generators for Rails 4.
Railsのジェネレータが生成するビューテンプレートをHaml化するhaml-railsのhamlit版のようです。Hamlという点では同じですがhaml gemへの依存をなくせますね。
pg
Pg is the Ruby interface to the PostgreSQL RDBMS.
RubyのPostgreSQLインタフェース。
pghero
A performance dashboard for Postgres
スロークエリのチェックやインデックスの状態などPostgreSQLの管理に役立つダッシュボードを提供するEngineのようです。
mastodonではDeviseのauthenticated routesを使ってマウントすることで管理者がアクセスできるようにしているようですね。
https://github.com/tootsuite/mastodon/blob/fe1ddc3b9614380367fa55f13df033e21c96747e/config/routes.rb#L11
authenticate :user, lambda { |u| u.admin? } do
mount Sidekiq::Web, at: 'sidekiq', as: :sidekiq
mount PgHero::Engine, at: 'pghero', as: :pghero
end
dotenv-rails
Autoload dotenv in Rails.
.env
ファイルに環境変数を書いておくと自動的に環境変数ENV
に読み込んでくれるようです。読み込みのタイミングはbefore_configurationなので、configで使いたいときはそれより前にDotenv::Railtie.load
とする必要があるようです。
https://github.com/tootsuite/mastodon/blob/fe1ddc3b9614380367fa55f13df033e21c96747e/config/application.rb#L13
Dotenv::Railtie.load
paperclip
Easy upload management for ActiveRecord
RailsのActiveRecordでファイルアップロード機能を書くのによく使われるgem
。最近はshrineなど後発のものに押されてる感ありますがよく見ますね。
https://github.com/tootsuite/mastodon/blob/e09ab2c0bdc0822886fa98b0019d4a447a2ee0d6/app/models/account.rb#L15
# Avatar upload
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '-quality 80 -strip' }
paperclip-av-transcoder
Audio/Video Transcoder for Paperclip using FFMPEG/Avconv
Paperclipでアップロードした動画をFFmpegやlibav(avconv)を使って変換するためのようです。
mastodonではContent-Typeをみて使うprocessorを切り換えるようにして使っていました。
https://github.com/tootsuite/mastodon/blob/bfbc2ca0d8dcef47f8581585b42f13b6b4c933d9/lib/paperclip/video_transcoder.rb
https://github.com/tootsuite/mastodon/blob/bfbc2ca0d8dcef47f8581585b42f13b6b4c933d9/app/models/media_attachment.rb#L88
def file_processors(f)
if f.file_content_type == 'image/gif'
[:gif_transcoder]
elsif VIDEO_MIME_TYPES.include? f.file_content_type
[:video_transcoder]
else
[:thumbnail]
end
end
aws-sdk
The official AWS SDK for Ruby. Provides both resource oriented interfaces and API clients for AWS services.
公式のRuby AWS SDKですね。
mastodonではアップロードファイルの保管先としてS3を使うときぐらいでしょうか。
https://github.com/tootsuite/mastodon/blob/6c83fec9715340bd178de0a8ba595bb4ad10eb1a/config/initializers/paperclip.rb#L10
addressable
Addressable is a replacement for the URI implementation that is part of Ruby's standard library.
標準ライブラリのURIのようにパースしたり、名前解決を行ってくれたり、正規化したりしてくれるようです。
mastodonではURLのバリデーションに使っているようです。
https://github.com/tootsuite/mastodon/blob/b330d1f000ef354a856c43aeaa27e079c89fc822/app/validators/url_validator.rb#L11
def compliant?(url)
parsed_url = Addressable::URI.parse(url)
!parsed_url.nil? && %w(http https).include?(parsed_url.scheme) && parsed_url.host
end
bootsnap
Boot large ruby/rails apps faster
Ruby/Railsアプリの起動高速化するgem。
Kernel#load
、Kernel#require
を書き換えてパス探索を高速化したり、コンパイル結果をキャッシュしたりするようです。
Adds bootsnap. Faster boot time #3176
cld3
Compact Language Detector v3 (CLD3) is a neural network model for language identification.
CLDというオープンソースの言語解析ライブラリのRubyバインディングのようです。
mastodonではトゥートの言語の自動検出に利用しています。
Language improvements, replace whatlanguage with CLD
class LanguageDetector
attr_reader :text, :account
def initialize(text, account = nil)
@text = text
@account = account
@identifier = CLD3::NNetLanguageIdentifier.new(1, 2048)
end
# (snip)
@identifier.find_language(text_without_urls)
ApplicationRecord.transaction do
status = account.statuses.create!(text: text,
thread: in_reply_to,
sensitive: options[:sensitive],
spoiler_text: options[:spoiler_text] || '',
visibility: options[:visibility],
language: detect_language_for(text, account),
application: options[:application])
attach_media(status, media)
end
def detect_language_for(text, account)
LanguageDetector.new(text, account).to_iso_s
end
devise
Flexible authentication solution for Rails with Warden
認証機能の手抜きによく使われる(僕もよく使ってしまう)そしてブラックボックスが嫌われがちなgemです。手早く一般的な機能を実装するのには便利だと思います。
devise-two-factor
Barebones two-factor authentication with Devise
Deviseで二段階認証(二要素認証)に対応する最小限の実装とのことです。Google Authenticatorなどに簡単に対応できるそうです。
https://github.com/tootsuite/mastodon/blob/93c13fe691750e8c7f0c90091bca2564b97ccba7/app/models/user.rb#L8
doorkeeper
Doorkeeper is an OAuth 2 provider for Rails and Grape.
OAuth2プロバイダの実装のようで、このあたりの記事が参考になりそうです。
mastodonのAPI認可に利用しているようです。
Search: doorkeeper
fast_blank
Provides a C-optimized method for determining if a string is blank
Cで書かれた高速なString#blank?
で置き換えるようです。
goldfinger
A Webfinger utility for Ruby
WebFingerクライアントのRuby実装のようです。
mastodonでは別のサーバー(mastodonインスタンス)のアカウントのフォローに利用しているようです。
https://github.com/tootsuite/mastodon/blob/0687ab8ae3c2573ba2aa1d37f62e3583d0c7ab01/app/controllers/remote_follow_controller.rb#L18
if @remote_follow.valid?
resource = Goldfinger.finger("acct:#{@remote_follow.acct}")
redirect_url_link = resource&.link('http://ostatus.org/schema/1.0/subscribe')
hiredis
Ruby wrapper for hiredis (protocol serialization/deserialization and blocking I/O)
RedisのCクライアントhiredisのRubyラッパーライブラリのようで、これ単体でも利用できるようですが、redis-rbとあわせて使うことでredis-rbの高速化が望めるようです。
htmlentities
A module for encoding and decoding (X)HTML entities.
文字実体参照や数値文字参照のエンコード・デコードができます。
http_accept_language
Find out which locale the user preferes by reading the languages they specified in their browser
ブラウザが送出したAccept-Languageヘッダーの扱いを簡単にします。リストアップした中から互換性のある言語を取り出したりできます。
mastodonではI18n.available_locales
の中から使えそうなlocaleを選ぶのに使っています。
https://github.com/tootsuite/mastodon/blob/f5cd1383231af6922dbab4f54b7d29eacfec9d9e/app/controllers/concerns/localized.rb#L35
def user_supplied_locale
http_accept_language.language_region_compatible_from(I18n.available_locales)
end
httplog
Log outgoing HTTP requests made from your application.
アプリケーションからの外部HTTP通信のログを記録してくれるので、たとえばAPI呼び出しの追跡などに役立つようです。
kaminari
Kaminari is a Scope & Engine based, clean, powerful, agnostic, customizable and sophisticated paginator for Rails 4+
ページネーションを実装する時にはまず使う、そんなgemです。
ActiveRecordだけでなく、Arrayなども同じようにページングできるのもよいです。
link_header
Converts conforming link headers to and from text, LinkHeader objects and corresponding (JSON-friendly) Array representations, also HTML link elements.
HTTPのLinkヘッダのパースや生成を簡単にするgemのようです。
mastodonではAPIでページネーションを実装するにあたり、前後のパスをクライアントに伝える際などに使っているようです。
https://github.com/tootsuite/mastodon/blob/e2a1b574ab4ec5dd07dbc5c317bcc3718f13c19b/app/controllers/api_controller.rb#L63
def set_pagination_headers(next_path = nil, prev_path = nil)
links = []
links << [next_path, [%w(rel next)]] if next_path
links << [prev_path, [%w(rel prev)]] if prev_path
response.headers['Link'] = LinkHeader.new(links)
end
nokogiri
Nokogiri (鋸) is an HTML, XML, SAX, and Reader parser.
XMLビルダー、パーサーを提供します。
mastodonではどちらの用途としても使っているようです。
https://github.com/tootsuite/mastodon/blob/137100dcf38c0da0fe7044a4c92aa06eae02c420/app/views/well_known/webfinger/show.xml.ruby#L1
Nokogiri::XML::Builder.new do |xml|
xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
xml.Subject @canonical_account_uri
xml.Alias TagManager.instance.url_for(@account)
xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: TagManager.instance.url_for(@account))
xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom'))
xml.Link(rel: 'salmon', href: api_salmon_url(@account.id))
xml.Link(rel: 'magic-public-key', href: "data:application/magic-public-key,#{@magic_key}")
xml.Link(rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_follow_url}?acct={uri}")
end
end.to_xml
xml = Nokogiri::XML(body)
xml.encoding = 'utf-8'
if xml.root.name == 'feed'
oj
The fastest JSON parser and object serializer.
高速なJSONライブラリ。
ostatus2
Toolset for interacting with the OStatus2 suite of protocols
PubSubHubbubを使ってフィードの更新通知したり、Salmon(サーモン)Protocolでフィードにコメントを付けたりするのに使えるようです。
コメント分散問題は“サーモン・プロトコル”で解決!? - @IT
Mastodon OStatus API の叩き方
mastodonではgoldfingerとあわせて別のサーバー(mastodonインスタンス)のユーザーのfollow/unfollow/like/unlikeなどの実装に使っているようです。
https://github.com/tootsuite/mastodon/blob/6d6a429af8fe4bd92ed497f401676353fdc603e0/app/services/favourite_service.rb#L16
https://github.com/tootsuite/mastodon/blob/f722bd2387df9163760014e9555928ec487ae95f/app/workers/notification_worker.rb#L9
https://github.com/tootsuite/mastodon/blob/50660d54e8cabd08fee649a6abc26f35a8d7a82c/app/services/send_interaction_service.rb
# Send an Atom representation of an interaction to a remote Salmon endpoint
# @param [String] Entry XML
# @param [Account] source_account
# @param [Account] target_account
def call(xml, source_account, target_account)
envelope = salmon.pack(xml, source_account.keypair)
salmon.post(target_account.salmon_url, envelope)
end
ox
A fast XML parser and object serializer that uses only standard C lib.
Cだけで書かれたlibxmlなどに依存しない、高速なXMLパーサ&オブジェクトシリアライザのようです。
XMLパーサとしてNokogiriより2倍以上高速で、&オブジェクトシリアライザとしてMarshal.dumpより最大6倍高速で、SAXではNokogiriよりも40倍、LibXMLよりも13倍高速という謳い文句です。
mastodonではAtomの生成に利用しているようです。
https://github.com/tootsuite/mastodon/blob/15ec4ae07b17821625bd2ca1088a7573a7ed128c/app/lib/atom_serializer.rb#L8
document = Ox::Document.new(version: '1.0')
document << element
('<?xml version="1.0"?>' + Ox.dump(element, effort: :tolerant)).force_encoding('UTF-8')
rabl
General ruby templating with json, bson, xml and msgpack support
API応答をDSLで柔軟に書けるというテンプレートシステムのようです。JSONだけでなくXML、MessagePackなど複数のフォーマットに対応しています。
mastodonでもAPI応答など利用されています。
Search: extension:rabl
rack-attack
A rack middleware for throttling and blocking abusive requests
ミドルウェアレベルでセーフリスト、ブラックリスト、スロットリングなど不正なリクエストからの防御を実装できるようです。
mastodonではAPIや、ログイン、ユーザー登録などのレート制限の実装に利用しているようです。
https://github.com/tootsuite/mastodon/blob/ff5baa5349ca7a5391cfa9e283d2f5e653f876ee/config/initializers/rack_attack.rb
# Rate limits for the API
throttle('api', limit: 300, period: 5.minutes) do |req|
req.ip if req.path =~ /\A\/api\/v/
end
# Rate limit logins
throttle('login', limit: 5, period: 5.minutes) do |req|
req.ip if req.path == '/auth/sign_in' && req.post?
end
now = Time.now.utc
match_data = request.env['rack.attack.throttle_data']['api']
response.headers['X-RateLimit-Limit'] = match_data[:limit].to_s
response.headers['X-RateLimit-Remaining'] = (match_data[:limit] - match_data[:count]).to_s
response.headers['X-RateLimit-Reset'] = (now + (match_data[:period] - now.to_i % match_data[:period])).iso8601(6)
rack-cors
Middleware that will make Rack-based apps CORS compatible.
ミドルウェアレベルでHTTPアクセス制御(CORS: Cross-Origin Resource Sharing)を実装できるようです。
mastodonではAPIのクロスオリジンアクセスの許可や、ヘッダのホワイトリストの指定などに利用しているようです。
https://github.com/tootsuite/mastodon/blob/0a1b0246003e19e80241d8711276db790a88235d/config/application.rb#L58
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '/api/*', headers: :any, methods: [:post, :put, :delete, :get, :options], credentials: false, expose: ['Link', 'X-RateLimit-Reset', 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-Request-Id']
resource '/oauth/token', headers: :any, methods: [:post], credentials: false
end
end
rack-timeout
Rack middleware which aborts requests that have been running for longer than a specified timeout.
ミドルウェアレベルでリクエストを受け取ってから結果を返すまでの待機時間や、POSTデータを受け取る際の受信待ち時間などを設定できるようです。
mastodonではproductionでのみサービスタイムアウトを設定しているようで、これにより長時間応答が返せない場合に処理を中断することができます。
https://github.com/tootsuite/mastodon/blob/5b12624847f6a599e1bbb3b24fc87c3b222e6716/config/initializers/timeout.rb#L5
Rack::Timeout::Logger.disable
Rack::Timeout.service_timeout = false
if Rails.env.production?
Rack::Timeout.service_timeout = 90
end
rails-i18n
A set of common locale data and translations to internationalize and/or localize your Rails applications.
Railsのデフォルト文字列を翻訳した辞書一式のようです。使いたい言語だけを選ぶこともできます。
rails-settings-cached
This is improved from rails-settings, added caching.
アプリケーション設定をドットファイルなどではなくデータベースに記録し、変更できるようにしたいとき簡単に実装できるgemです。
mastodonでは「サイト名」や「自由にユーザー登録できるようにするか」などの設定に利用しているようです。
https://github.com/tootsuite/mastodon/blob/d87ee1167e0f11d94a20e70e9228a3398e202bc8/app/controllers/auth/registrations_controller.rb#L32
redis
A Ruby client library for Redis
Key-Value StoreのひとつRedisのRubyクライアントライブラリで、Redis APIと1対1で対応するようです。hiredisと組み合わせて使うことで高速化するようです。
mastodonではsidekiqのバックエンドとして非同期処理の他、ActionCable(これは設定だけかも)、Node.jsによるStreaming APIなどに利用しているようです。
https://github.com/tootsuite/mastodon/blob/323671a653e22704f0d50be13d67bf6fe6ee3a2a/app/services/fan_out_on_write_service.rb#L61
def deliver_to_hashtags(status)
Rails.logger.debug "Delivering status #{status.id} to hashtags"
status.tags.pluck(:name).each do |hashtag|
Redis.current.publish("timeline:hashtag:#{hashtag}", @payload)
Redis.current.publish("timeline:hashtag:#{hashtag}:local", @payload) if status.local?
end
end
redis-namespace
Adds a Redis::Namespace class which can be used to namespace calls to Redis. This is useful when using a single instance of Redis with multiple, different applications.
Redisキーにnamespaceを使用できるようになるgemのようです。複数のアプリから1つのRedisサーバを使う場合など役立ちそうです。
namespace = ENV.fetch('REDIS_NAMESPACE') { nil }
if namespace
Redis.current = Redis::Namespace.new(namespace, redis: redis_connection)
else
Redis.current = redis_connection
end
rqrcode
rQRCode is a library for encoding QR Codes.
QRコード生成のライブラリのようです。
mastodonでは二段階認証(二要素認証)の際にスマートフォンに読み取らせるQRコードを生成するのに利用しているようです。
https://github.com/tootsuite/mastodon/blob/a8e1afc30a1f843943bb29e7385b8611ea3c29f4/app/controllers/settings/two_factor_auths_controller.rb#L50
ruby-oembed
oEmbed for Ruby
URLから埋め込み用コードを取得できるoEmbedという仕様のRuby実装のようです。oEmbedクライアントとしては、任意のoEmbedプロバイダのURLを指定するだけで、サムネイルや埋め込み用HTMLなどを取得できるようです。また、独自のoEmbedプロバイダを作るのにも使えるようです。
mastodonでは現在のところGemfileにはあるものの使われていなさそうでした。
個別のトゥートページのLinkタグで示されるapplication/json+oembed
はありますが、
https://github.com/tootsuite/mastodon/blob/389f8f824909d60b7560248465416bd4bed92b6b/app/views/stream_entries/show.html.haml#L3
- content_for :header_tags do
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/
%link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/
その実装は、rablで書かれていました。
https://github.com/tootsuite/mastodon/blob/389f8f824909d60b7560248465416bd4bed92b6b/app/views/api/oembed/show.json.rabl
# frozen_string_literal: true
object @stream_entry
node(:type) { 'rich' }
node(:version) { '1.0' }
node(:title, &:title)
node(:author_name) { |entry| entry.account.display_name.blank? ? entry.account.username : entry.account.display_name }
node(:author_url) { |entry| account_url(entry.account) }
node(:provider_name) { site_hostname }
node(:provider_url) { root_url }
node(:cache_age) { 86_400 }
node(:html) { |entry| "<iframe src=\"#{embed_account_stream_entry_url(entry.account, entry)}\" style=\"width: 100%; overflow: hidden\" frameborder=\"0\" width=\"#{@width}\" height=\"#{@height}\" scrolling=\"no\"></iframe>" }
node(:width) { @width }
node(:height) { @height }
これによりoEmbedに対応したサービスでmastodonのトゥートのURLを貼り付けると、特別な設定をせずとも埋め込み表示されます。
たとえばはてなブログなどは対応しています。
sanitize
Sanitize is a whitelist-based HTML and CSS sanitizer. Given a list of acceptable elements, attributes, and CSS properties, Sanitize will remove all unacceptable HTML and/or CSS from a string.
ホワイトリスト方式のサニタイズができるgem。許可する要素や属性など細かく設定できるようです。
mastodonでは用途ごとにサニタイズ設定を用意し、ヘルパーやサービスクラスで使い分けているようです。
MASTODON_OEMBED ||= freeze_config merge(
RELAXED,
elements: RELAXED[:elements] + %w(audio embed iframe source video),
attributes: merge(
RELAXED[:attributes],
'audio' => %w(controls),
'embed' => %w(height src type width),
'iframe' => %w(allowfullscreen frameborder height scrolling src width),
'source' => %w(src type),
'video' => %w(controls height loop width),
'div' => [:data]
),
card.html = Formatter.instance.sanitize(response.html, Sanitize::Config::MASTODON_OEMBED)
sidekiq
Simple, efficient background processing for Ruby.
非同期処理を実現するgemです。
Rails 4.2以上ではActive Jobというフレームワークが導入され、Sidekiqもそのバックエンドとして選択できるという扱いになりましたが、mastodonの場合はSidekiqをそのまま利用しているようです。
https://github.com/tootsuite/mastodon/blob/389f8f824909d60b7560248465416bd4bed92b6b/app/workers/after_remote_follow_request_worker.rb#L4
class AfterRemoteFollowRequestWorker
include Sidekiq::Worker
sidekiq_options queue: 'pull', retry: 5
def perform(follow_request_id)
follow_request = FollowRequest.find(follow_request_id)
updated_account = FetchRemoteAccountService.new.call(follow_request.target_account.remote_url)
if target_account.local?
NotifyService.new.call(target_account, follow_request)
else
NotificationWorker.perform_async(build_follow_request_xml(follow_request), source_account.id, target_account.id)
AfterRemoteFollowRequestWorker.perform_async(follow_request.id)
end
sidekiq-scheduler
Light weight job scheduling extension for Sidekiq that adds support for queueinga jobs in a recurring way.
SidekiqでCRONなどのような定期処理を実装するgemです。
複数のサーバインスタンスがあるとき、多重実行されるのかどうか?そのケアは必要か?はちょっと試してないのでよくわかりません。(誰か詳しい方教えてください…)
:schedule:
subscriptions_scheduler:
cron: '0 5 * * *'
class: Scheduler::SubscriptionsScheduler
# frozen_string_literal: true
require 'sidekiq-scheduler'
class Scheduler::SubscriptionsScheduler
include Sidekiq::Worker
def perform
logger.info 'Queueing PuSH re-subscriptions'
expiring_accounts.pluck(:id).each do |id|
Pubsubhubbub::SubscribeWorker.perform_async(id)
end
end
private
def expiring_accounts
Account.expiring(1.day.from_now).partitioned
end
end
sidekiq-unique-jobs
Handles various types of unique jobs for Sidekiq
Sidekiqで同じジョブが同時に複数実行されないようにできるようです。
mastdonの場合は、2週間ぶりにログインしたユーザーのメンションをDBから探すという重めの処理について1回だけ実行したい、ということで利用しているようです。
https://github.com/tootsuite/mastodon/blob/5d710b1139b34f2ed6bd556f448fa7248354e758/app/controllers/application_controller.rb#L44
# If the sign in is after a two week break, we need to regenerate their feed
RegenerationWorker.perform_async(current_user.account_id) if current_user.last_sign_in_at < 14.days.ago
class RegenerationWorker
include Sidekiq::Worker
sidekiq_options queue: 'pull', backtrace: true, unique: :until_executed
simple-navigation
A ruby gem for creating navigations (with multiple levels) for your Rails, Sinatra or Padrino applications. Render your navigation as html list, link list or breadcrumbs.
ナビゲーションやパンくずリストを簡単に作れるgemのようです。
mastodonでは管理画面のナビゲーションに利用しているようです。
https://github.com/tootsuite/mastodon/blob/55e150352204bc790345cf81ef02bfcb1d7e0594/config/navigation.rb
https://github.com/tootsuite/mastodon/blob/0d83569899155e5d5c17fff0c69e533df2f34d42/app/views/layouts/admin.html.haml#L11
simple_form
Forms made easy!
Railsのフォームをスッキリ書けるDSLを提供するgemのようです。
mastodonではログインページ等各種フォームで利用しているようです。
https://github.com/tootsuite/mastodon/blob/23b997ae55655ccae6a9a9e424a3596c9165a481/app/views/auth/sessions/new.html.haml#L4
= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
= f.input :email, autofocus: true, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password') }
.actions
= f.button :button, t('auth.login'), type: :submit
statsd-instrument
A StatsD client for Ruby apps.
StatsDののRubyクライアントで、アプリケーションのメトリクスの取得と計測を行えるようです。
mastodonではActiveSupport::Notificationsを使ってActionControllerの処理を時間を計測しているようです。
https://github.com/tootsuite/mastodon/blob/f6a5977f0b2986b15ca8254123053e1a59647cd1/config/initializers/statsd.rb
ActiveSupport::Notifications.subscribe(/performance/) do |name, _start, _finish, _id, payload|
action = payload[:action] || :increment
measurement = payload[:measurement]
value = payload[:value]
key_name = clean_name("#{name}.#{measurement}")
StatsD.send(action.to_s, key_name, (value || 1))
end
ActiveSupport::Notifications.subscribe(/process_action.action_controller/) do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
# (snip)
ActiveSupport::Notifications.instrument :performance, action: :measure, measurement: "#{key}.total_duration", value: event.duration
ActiveSupport::Notifications.instrument :performance, action: :measure, measurement: "#{key}.db_time", value: event.payload[:db_runtime]
ActiveSupport::Notifications.instrument :performance, action: :measure, measurement: "#{key}.view_time", value: event.payload[:view_runtime]
ActiveSupport::Notifications.instrument :performance, measurement: "#{key}.status.#{status}"
end
twitter-text
A gem that provides text handling for Twitter
TwitterにツイートするテキストのURL自動リンク、文字数の正確なカウントなどの面倒をみてくれるようです。
mastodonではトゥートの自動リンクに利用しているようです。
https://github.com/tootsuite/mastodon/blob/70891a99a97bc1ca14a8ded13a5cd45b648b92b3/app/lib/formatter.rb
https://github.com/tootsuite/mastodon/blob/70891a99a97bc1ca14a8ded13a5cd45b648b92b3/spec/lib/formatter_spec.rb
webpacker
Use Webpack to manage app-like JavaScript modules in Rails
アセット管理をSprockets/BrowserifyからWebpackに切り替えたことで追加されました。
Webpacker gemについて調べる時間がなかったのでとりあえずほかの記事
今は支えていないgems
記事作成時点で使われていたけど、その後Gemfileから消えたgemはここに残しておきます。
font-awesome-rails
I like font-awesome. I like the asset pipeline. I like semantic versioning. If you do too, you're welcome.
font-awesomeとAsset Pipelineとセマンティック・バージョニングが好きな人に。
アセット管理をSprockets/BrowserifyからWebpackに切り替えた影響で削除したようです。
best_in_place
A RESTful unobtrusive jQuery Inplace-Editor and a helper as a Rails Gem
編集したいところをページ遷移なしにそのまま編集できる機能を簡単に実現できるようにするEngineのようです。mastodonでは管理画面のサイト設定で使っているようです・・・が、そのうち無くなる気がします。
https://github.com/tootsuite/mastodon/blob/d90d23699ca611f05d8def40109505251507fa46/app/views/admin/settings/index.html.haml#L15
%td= best_in_place @settings['site_contact_username'], :value, url: admin_setting_path(@settings['site_contact_username']), place_holder: t('admin.settings.contact_information.username')
autoprefixer-rails
Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website.
CSSベンダープレフィックスを付与してくれるAutoprefixerを、Sprocketsで使ってくれるようになるようです。
react-rails
Render components in views or controller actions.
RailsのViewとReact Componentの橋渡しをしてくれます。
mastodonでは、app/assets/javascripts/components/containers/mastodon.jsxをホームのViewに置くことでRails View内にTweetDeckっぽいSPAを置いています。react-rails単体でもJSXのプリコンパイルも対応しているはずですが、それについてはbrowserify-railsで行っていました。
https://github.com/tootsuite/mastodon/blob/0d83569899155e5d5c17fff0c69e533df2f34d42/app/views/home/index.html.haml#L6
- content_for :header_tags do
%script#initial-state{:type => 'application/json'}!= json_escape(render(file: 'home/initial_state', formats: :json))
= javascript_include_tag 'application', integrity: true, crossorigin: 'anonymous'
= react_component 'Mastodon', default_props, class: 'app-holder', prerender: false
browserify-rails
Browserify + Rails = CommonJS Heaven
SprocketsでCommonJSを使えるようにする方法の1つです。
mastodonではBabelifyと組み合わせてBabelのes2015とreactのプリセットを利用しているようです。
https://github.com/tootsuite/mastodon/blob/0a1b0246003e19e80241d8711276db790a88235d/config/application.rb#L71
config.browserify_rails.source_map_environments << 'development'
config.browserify_rails.commandline_options = '--transform [ babelify --presets [ es2015 react ] ] --extension=".jsx"'
config.browserify_rails.evaluate_node_modules = true
const Mastodon = React.createClass({
# (snip)
});
export default Mastodon;
//= require_tree ./components
window.Mastodon = require('./components/containers/mastodon');
アセット管理をSprockets/BrowserifyからWebpackに切り替えた影響で削除したようです。
whatlanguage
WhatLanguage rapidly detects the language of a sample of text
文字列からどの言語で書かれているか検出できるそうです。
mastodonではトゥートの内容から言語を検出するのに利用しているようです。
https://github.com/tootsuite/mastodon/blob/297c11dba2864b20992cd3f98282f5ce35d5d144/app/lib/language_detector.rb#L12
def to_iso_s
WhatLanguage.new(:all).language_iso(text) || default_locale.to_sym
end
https://github.com/tootsuite/mastodon/blob/297c11dba2864b20992cd3f98282f5ce35d5d144/app/services/post_status_service.rb#L22
https://github.com/tootsuite/mastodon/blob/297c11dba2864b20992cd3f98282f5ce35d5d144/app/services/post_status_service.rb#L56
def call(account, text, in_reply_to = nil, options = {})
media = validate_media!(options[:media_ids])
status = account.statuses.create!(text: text,
thread: in_reply_to,
sensitive: options[:sensitive],
spoiler_text: options[:spoiler_text] || '',
visibility: options[:visibility],
language: detect_language_for(text, account),
application: options[:application])
# (snip)
end
def detect_language_for(text, account)
LanguageDetector.new(text, account).to_iso_s
end
検出精度の低さが問題になってCLDというオープンソースの言語解析ライブラリベースのcld2
gemに置き換えられ、その後さらにcld3
gemに置き換えられたようです。