- 開発
週刊Railsウォッチ(20191021)Rails 6でhas_many関連の修正やSprockets 4.0対応、Shrine 3.0がリリース、Minitestスタイルガイドほか
こんにちは、hachi8833です。スマホで確定申告できるようになるそうです。
やっと来年からiPhoneでe-Taxができる! https://t.co/HHJamYgNBB
— Haruhiko Okumura (@h_okumura) October 16, 2019
つっつきボイス:「スマホで確定申告したい人っているんでしょうか?😆」「スマホとかタブレットでやらないと間に合わないシチュエーションはあるかもですね☺️」
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
⚓Rails: 先週の改修(Rails公式ニュースより)
今回はコミットリストから見繕いました。has_many
関連の修正が目に付きました。
⚓(master)belongs_to
からhas_many
へのinverseをサポート
- PR: Add support for belongs_to to has_many inversing. by gmcgibbon · Pull Request #34533 · rails/rails
# activerecord/lib/active_record/associations/belongs_to_association.rb#L111
- # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
- # has_one associations.
def invertible_for?(record)
+ inverse = inverse_reflection_for(record)
+ inverse && inverse.has_one?
+ inverse_reflection_for(record)
end
# activerecord/lib/active_record/associations/collection_association.rb#L288
+ def target=(record)
+ case record
+ when Array
+ super
+ else
+ add_to_target(record)
+ end
+ end
つっつきボイス:「belongs_to
からhas_many
へのcollectionのinverseはありそうでなかったんですね😳」「ドキュメントの更新と実際の挙動が合ってなかったので修正したそうです」
「ところでこのr?
という「合ってる?」表現↓、ちょっと便利かなと思いました😋」「right?をそこまで略すのはどうかと😆」「SNSのチャット感覚というか😆」「そのぐらいフルで書いてもいいのでは😆」「了解を『り』とか『りょ』と書くみたいな😆」
⚓(master)inverse_of:
を指定したhas_many
のレコード追加で関連付けのコールバックが発火しないように修正
has_many
でinverse_of:
を追加した場合に関連付けのコールバックが走るのを止める。
上の#34533に関連して、has_many
リレーションでinverse_of:
を静かに設定したい、つまり新たに追加したレコード用のロジックをトリガしたくない。
has_many
のinverseを設定すると既存のアプリケーションが壊れる可能性が非常に高いが、これが正しい動作。挙動を選べるようにするプルリクを別途投げて、アプリ側を調整する時間を取れるようにする。
同PRより大意
修正はわずか1箇所です↓。
# activerecord/lib/active_record/associations/collection_association.rb#L293
def target=(record)
case record
when Array
super
else
- add_to_target(record)
+ add_to_target(record, true)
end
end
つっつきボイス:「今回はhas_many
関連の修正が多くて、特にこれは修正は1箇所だけですがbreaking changeになってますね」「ははぁ😳、こういう変更をバシッと入れるのがすごいな〜って」「さすがに影響大きそうなので、デフォルトではオフにするそうです↓」「使う側はこういう変更追いかけるの大変そう😅」
以下がその後に入った、挙動を選べるようにする修正ですね。config.active_record.has_many_inversing
という設定(デフォルトはfalse)が追加されています。
なお、以下の記事では「Rails 4.1以降ではinverseの自動検出機能がある」「inverseの自動検出はhas_many
、has_one
、belongs_to
でのみ効く」「関連付けにそれ以外のオプションを付けると自動検出されなくなる」ともあります。APIのActiveRecord::Associations::ClassMethods
の「Setting Inverses」にも同じ記述がありました。
参考: Rails 4.1+ automatically detects the :inverse_of an association - makandra dev
⚓Sprockets 4.0に合わせてテストスイートを修正
つっつきボイス:「先週取り上げたSprocketsのアップデート(ウォッチ20191015)に合わせてRails側も修正したようです」「ほほぉ〜😋」
application.css
とapplication.css.erb
を両方使うのは適切ではなくなった(ナイス変更!)//= link_directory ../javascripts .js
でJavaScriptをデフォルトで再追加することでリンクするのを廃止
- (これはデフォルトにしたい気がするが、今はWebpackerが望ましいのでJSのテストのためだけに一応足しておいた)
- アセットのデバッグモードが変わった
同PRより大意
「ついでにこんな記事↓も見つけたんですが、Rails 6がSprockets 4.0に対応する前にSprocketsを使ってみて、上の修正と同じような箇所でハマったようです😇」「急ぎすぎ😆」「ついでにSprockets 3と4の違いについても追っていますね☺️」
⚓has_many
のeager loadingのエッジケースを修正
eager loadingの実行結果(のレコード)は重複解除される。
これはhas_many
のeager loadではできているが、できていない組み合わせのケースがあった。
同PRより大意
# activerecord/lib/active_record/relation/finder_methods.rb#L381
def apply_join_dependency(eager_loading: group_values.empty?)
join_dependency = construct_join_dependency(
eager_load_values + includes_values, Arel::Nodes::OuterJoin
)
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
- if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
+ reflections = join_dependency.reflections + joins_values.map { |joins_value| reflect_on_association(joins_value) }.reject(&:blank?)
+ if eager_loading && !using_limitable_reflections?(reflections)
if has_limit_or_offset?
limited_ids = limited_ids_for(relation)
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
end
relation.limit_value = relation.offset_value = nil
end
if block_given?
yield relation, join_dependency
else
relation
end
end
# activerecord/test/cases/finder_test.rb#1339
def test_eager_load_for_no_has_many_with_limit_and_joins_for_has_many
relation = Post.eager_load(:author).joins(:comments)
assert_equal 5, relation.to_a.size
assert_equal relation.limit(5).to_a.size, relation.to_a.size
end
つっつきボイス:「またhas_many
😆」「まただ〜😆」「SQLの結果では複数行になるけどinstantiateするときに1つになるのが本来で、エッジケースでそうならないバグがあったということか: テストコード↑と#37356の再現手順↓を見る方がわかりやすいかも🤔」
# #37356より
class Post < ActiveRecord::Base
has_many :comments
has_one :author
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class Author < ActiveRecord::Base
belongs_to :post
end
class BugTest < Minitest::Test
def test_in_batches_corner_case
posts = 5.times.map do
post = Post.create!
post.comments << Comment.create!
post
end
multiple_comments = posts[2]
multiple_comments.comments << Comment.create!
post_count = 0
unbatched_query = Post.eager_load(:author).joins(:comments)
unbatched_query.find_each(batch_size: 2) do |post|
post_count += 1
end
assert_equal unbatched_query.to_a.count, post_count
end
end
「eager loadingってこれですね↓」「deduplicateって口で言うの大変😅」「デデュプリケート😆」
参考: eager loadingって何? - おもしろwebサービス開発日記
参考: ActiveRecordのincludes, preload, eager_load の個人的な使い分け | Money Forward Engineers' Blog
⚓キーが多数の場合のread_multi_entries
のパフォーマンスを改善
ActiveSupport::Cache::Store#read_multi_entries
を以下の3点について少々リファクタリングし、フェッチしたキーが増加したときのパフォーマンスを若干改善した。個人的には読みやすさも向上したと思う。
each
をeach_with_object
に変更。これによってハッシュを冒頭で宣言して最後に返す必要がなくなった。- キャッシュエントリが見当たらない場合にローカル変数
version
の算出を回避した。- 何もしない場合の条件を削除した。
同PRより大意
================================== A few keys ==================================
Warming up --------------------------------------
read_multi 12.831k i/100ms
fast_read_multi 14.510k i/100ms
Calculating -------------------------------------
read_multi 146.288k (±26.0%) i/s - 654.381k in 5.010593s
fast_read_multi 172.428k (±25.9%) i/s - 783.540k in 5.023852s
Comparison:
fast_read_multi: 172427.5 i/s
read_multi: 146288.2 i/s - same-ish: difference falls within error
================================== Many keys ===================================
Warming up --------------------------------------
read_multi 196.000 i/100ms
fast_read_multi 279.000 i/100ms
Calculating -------------------------------------
read_multi 1.984k (± 6.7%) i/s - 9.996k in 5.062818s
fast_read_multi 2.823k (± 7.6%) i/s - 14.229k in 5.072824s
Comparison:
fast_read_multi: 2823.1 i/s
read_multi: 1984.3 i/s - 1.42x slower
# activesupport/lib/active_support/cache.rb#L585
def read_multi_entries(names, **options)
- results = {}
- names.each do |name|
- key = normalize_key(name, options)
+ names.each_with_object({}) do |name, results|
+ key = normalize_key(name, options)
+ entry = read_entry(key, **options)
+
+ next unless entry
+
version = normalize_version(name, options)
- entry = read_entry(key, **options)
-
- if entry
- if entry.expired?
- delete_entry(key, **options)
- elsif entry.mismatched?(version)
- # Skip mismatched versions
- else
- results[name] = entry.value
- end
+
+ if entry.expired?
+ delete_entry(key, **options)
+ elsif !entry.mismatched?(version)
+ results[name] = entry.value
end
end
- results
end
つっつきボイス:「割と読みやすいリファクタリングかなと思いました☺️」「names.each do |name|
をnames.each_with_object({}) do |name, results|
に変えたことでresults = {}
を書かなくてよくなったと、なるほど😋」「余分な条件も削除した」「そして1.42倍速くなって読みやすくなった🎉」「冒頭にresults = {}
みたいな空の変数初期化を置くのって何となく悔しいですよね😆」「たしかに😆」
⚓Rails
⚓Capistranoに対話処理を取り入れる(Hacklinesより)
# 同記事より
namespace :rails do
desc "Start a rails console"
task :console do
exec_interactive("rails console")
end
desc "Start a rails dbconsole"
task :dbconsole do
exec_interactive("rails dbconsole")
end
def exec_interactive(command)
host = primary(:web).hostname
env = "RAILS_ENV=#{fetch(:rails_env)}" # add other ENV variables
command = "cd #{release_path}; #{env} bundle exec #{command}"
puts "Running command on #{host}:"
puts " #{command}\n\n"
exec %(ssh #{host} -t "sh -c '#{command}'")
end
end
つっつきボイス:「CapistranoはRuby製の自動化・デプロイツールでお馴染みですが、それに対話的処理を加えてみたという短い記事です」「Capistranoまだ使ったことなくて😅」「morimorihogeさんはCapistranoいいよって言ってました(ウォッチ20181210)」「お〜見てみます😋」
「バッチでえいやする代わりに対話的にやりたいときもあるんでしょうか?」「デプロイってだいたいバッチでえいやが多い気もしますけど😆」
「Rubyのは知りませんが、デプロイツールはいろいろ使いました☺️」「ちなみにどんなのをお使いでした?」「古いところではmavenとか↓」「おぉ知りませんでした😳」「Apache Antもそうかなと思ったらこっちはビルドツールだった😆」「どちらもJava方面なんですね」「何しろ昔からあるので古いといえば古いかな〜👴」「mavenって辞書見ると『物知り、専門家、達人、玄人、通、目利き、大御所』とか強そうな意味が並んでる😆」
⚓Railsのビューでstrftime
を直書きするのはたぶん間違い
# 同記事より: config/initializers/time_formats.rb
Date::DATE_FORMATS[:stamp] = "%Y%m%d" # YYYYMMDD
Time::DATE_FORMATS[:stamp] = "%Y%m%d%H%M%S" # YYYYMMDDHHMMSS
つっつきボイス:「この記事ではstrftime
をビューに直書きする代わりに、書式をグローバル定数に置いてるみたいなんですけど、それもどうなんだろうと思って」「お、最初自分もグローバル定数かと思ったけど、このDATE_FORMATS
はどうやらRails組み込みの機能↓のようで、そこに:stamp
という独自の書式を追加していますね」「あ、そうでしたか😅」「グローバル定数で書くのは止めた方がいいけど、機能としてあるなら使っていいと思います😋」
- API:
Date
DATE_FORMATS = { short: "%d %b", long: "%B %d, %Y", db: "%Y-%m-%d", number: "%Y%m%d", long_ordinal: lambda { |date| day_format = ActiveSupport::Inflector.ordinalize(date.day) date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007" }, rfc822: "%d %b %Y", iso8601: lambda { |date| date.iso8601 } }
- API:
Time
DATE_FORMATS = { db: "%Y-%m-%d %H:%M:%S", number: "%Y%m%d%H%M%S", nsec: "%Y%m%d%H%M%S%9N", usec: "%Y%m%d%H%M%S%6N", time: "%H:%M", short: "%d %b %H:%M", long: "%B %d, %Y %H:%M", long_ordinal: lambda { |time| day_format = ActiveSupport::Inflector.ordinalize(time.day) time.strftime("%B #{day_format}, %Y %H:%M") }, rfc822: lambda { |time| offset_format = time.formatted_offset(false) time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}") }, iso8601: lambda { |time| time.iso8601 } }
参考: Railsで日付/時刻のフォーマットを設定するTips - Rails Webook
参考: RailsのTime::DATE_FORMATS[:default]は変更しないほうがいい - Qiita
↑2番目の記事ではI18nの機能を使う方法も紹介されています。
⚓スクリーンキャスト: 13分でわかるRails tipsいろいろ(Ruby Weeklyより)
- Screencast: Ruby on Rails Tips and Tricks | Drifting Ruby
つっつきボイス:「Railsのちょっとした便利ワザ集なんですが、スクリーンキャストって見ます?」「いや〜自分は見ませんけど☺️」(少し流し見)
「これが10分あまり続くんですね😅」「まあ10分ならまだ短い方かも: 1時間とかかかるのもざらにありますし😆」
「ところでparameterってプラミターとかプウァミターみたいに発音してるんですね😳」「割とそんな感じですね: 「ラ」を強く言うのがポイント」「果物のプラムかと思っちゃいました😅」「あとSQLもあっちの人はだいたいスィークォー(sequel)と言ってます😆」「エスキューエルって言うのは日本人ぐらい?」「たまに言う気もしますけどsequel多いですね☺️」
なお一般的な意味のsequelは「(ドラマなどの)続編」です。
「スクリーンキャストで思い出したんですけど、昔大学の先輩がライブコーディングをやってみせたときになかなかうまくいかなくて、あれはある意味特殊な才能が必要なんじゃないかって話になりました😆」「あ〜たしかに」「本番でいろいろハプニングが起きうることを見越してライブコーディングするのはホント大変😭」「録画を流す方がまだやりやすいかも: 前にも紹介しましたけど、jnchitoさんは銀座Railsのときに録画を倍速再生して見せてくれました↓」「お〜」
8/29の #ginzarails で使ったライブコーディング動画(?)を公開しました!ただし、今回はBOOTHでの有料販売にさせてもらってます。また、当日は倍速再生でしたが、こちらは等速です▶️
【動画】プログラマがコードを書きながら考えること 〜動画でわかるWebクローラー開発〜 https://t.co/RPmNL67DMj— Junichi Ito (伊藤淳一) (@jnchito) September 8, 2019
⚓Shrine 3.0がリリース(Awesome Rubyより)
もう3.0.1になっていますね。
コアの再設計以外はほとんどがプラグイン関連の変更のようです。
Shrine::Attacher
を再設計- versionsプラグインを書き直し
- mirroringプラグインを追加
- ROMやHanamiとの統合を強化
つっつきボイス:「お、Shrineのアップグレードって前にもつっつきで見たような覚えありますね」「あ、アップグレード予告を取り扱ったような😅」
↓こちらでした。
週刊Railsウォッチ(20190902)Ruby 2.6.4セキュリティ修正リリース、スライド「All About Ruby in 2019」、Shrine gem 3.0に入る新機能ほか
「ともあれShrineが3.0でだいぶ強力になったようです🎉」「サイトデザインが新しくなったという見出しがトップ😆」「Attacher
というクラスの設計をActive Recordから切り離して他でも使えるようになったり、プラグインを追加更新廃止したり」「ところでなぜShrineという名前なんでしょうね😆」「どの辺が神社仏閣なのかわかりませんし😆」
# 同記事より: 単独でも使えるように設計見直し
attacher = ImageUploader::Attacher.new
attacher.attach(file)
attacher.file #=> #<Shrine::UploadedFile>
attacher.url #=> "https://my-bucket.s3.amazonaws.com/path/to/image.jpg"
shrine: 遺骨・遺物をおさめた箱、櫃(ヒツ)が原義
「Algolia?」「ShrineのサイトがAlgoliaで検索できるようになったと記事にありますね↓: AlgoliaについてはTechRachoにも記事がありますのでどうぞ😋」
⚓その他Rails
- 元記事: How to build a Rails application with VueJS using JSX(Ruby Weeklyより)
- 元記事: Rails 6 Sidekiq Queues - DEV Community 👩💻👨💻(Hacklinesより)
⚓Ruby
⚓Minitestスタイルガイドが登場(Ruby Weeklyより)
つっつきボイス:「rubocopチームが作ってくれたそうですが、シンプルなのがいいなと思って😋」「たしかにあれっと思うぐらい短いですね」「RSpecのスタイルガイドは@willnetさんが日本語にしてくれています↓が、これと比べても短い」
参考: willnet/rspec-style-guide: 可読性の高いテストコードを書くためのお作法集
なお以下は中の人Batsovさんのブログです。rubocop-minitestは進行中のようです。
私はRSpecが大好きですが、Minitestのシンプルな設計にも大いに敬意を払ってます。
私たちRuboCopチームが現在rubocop-minitestに取り組み中であることをお知らせします。
同記事より大意
- サイト: Home - A RuboCop extension focused on enforcing Minitest best practices and coding conventions.
- リポジトリ: rubocop-hq/rubocop-minitest: Code style checking for Minitest files.
⚓active_hash: ハッシュをActive Recordモデルっぽくリードオンリーアクセス
ruby-jp Slackで見かけました。
つっつきボイス:「RubyのハッシュをActive Recordみたいにするgemで★700超えてますが、どんな人が使うのかな?🤔」
こちらの記事では、都道府県のように更新されないデータをactive_hashで扱ってますね↓。
参考: active_hash[gem]でデータの入ったテーブル作成 - Qiita
「ActiveHash::Base
を継承すると、ハッシュのキーがメソッドで生えてくるという」
# 同リポジトリより
class Country < ActiveHash::Base
self.data = [
{:id => 1, :name => "US"},
{:id => 2, :name => "Canada"}
]
end
country = Country.new(:name => "Mexico")
country.name # => "Mexico"
country.name? # => true
「クラスメソッドやインスタンスメソッドもいかにもActive Record風」「おほ、なるほどなるほど☺️」
# クラスメソッド
Country.all # => returns all Country objects
Country.count # => returns the length of the .data array
Country.first # => returns the first country object
Country.last # => returns the last country object
Country.find 1 # => returns the first country object with that id
Country.find [1,2] # => returns all Country objects with ids in the array
Country.find :all # => same as .all
Country.find :all, args # => the second argument is totally ignored, but allows it to play nicely with AR
Country.find_by_id 1 # => find the first object that matches the id
Country.find_by(name: 'US') # => returns the first country object with specified argument
Country.find_by!(name: 'US') # => same as find_by, but raise exception when not found
Country.where(name: 'US') # => returns all records with name: 'US'
Country.where.not(name: 'US') # => returns all records without name: 'US'
# インスタンスメソッド
Country#id # => returns the id or nil
Country#id= # => sets the id attribute
Country#quoted_id # => returns the numeric id
Country#to_param # => returns the id as a string
Country#new_record? # => returns true if is not part of Country.all, false otherwise
Country#readonly? # => true
Country#hash # => the hash of the id (or the hash of nil)
Country#eql? # => compares type and id, returns false if id is nil
# 以下はメタプロで生える
Country#name # => returns the passed in name
Country#name? # => returns true if the name is not blank
Country#name= # => sets the name
「こういう書き方ってしたい方ですか?」「いやぁ〜、今見たときはふむふむと思いましたけど、このgemが入ってきたらまた書き方覚えないといけないのかなって😅」「まあ業務コードに入れるなら確認取ってからでしょうね😆」
「Rubyだとハッシュのキーを.
で呼べないのが悲しいって言う人をそこそこ見かけたりしますけど、Ruby自身にこういうのは入れないのかな?🤔」「どうでしょう😆、求められているなら入るかもしれませんけど、私は.
でハッシュキー呼べなくても別にいいじゃんって思いますし☺️」
後で探すと、frozen_recordという少し似た感じのgemがありました。
⚓Ruby 2.7のArrayにintersection
とunion
とdifference
が追加(RubyFlowより)
# 同記事より
[ "a", "b", "z" ].intersection([ "a", "b", "c" ], [ "b" ]) # => [ "b" ]
[ "a", "b", "c" ].union( [ "c", "d", "a" ] ) #=> [ "a", "b", "c", "d" ]
[ 1, 4, 7, 8, "a", :t ].difference([ 4, :t ]) #=> [ 1, 7, 8, "a" ]
つっつきボイス:「Ruby 2.7のArrayに集合論っぽいメソッドが入るそうです」「RubyのSet
的なことがArrayでもできるようになったと🤔」「しょっちゅうは使わなくても、たまに欲しくなりそう😆」
- instance method
Set#&
(Ruby 2.6.0) --intersection
はエイリアス - instance method
Set#+
(Ruby 2.6.0) --union
はエイリアス - instance method
Set#-
(Ruby 2.6.0) --difference
はエイリアス
⚓parallel: Rubyで並列処理(Ruby Weeklyより)
# 同記事より
# 2 CPUs -> work in 2 processes (a,b + c)
results = Parallel.map(['a','b','c']) do |one_letter|
expensive_calculation(one_letter)
end
# 3 Processes -> finished after 1 run
results = Parallel.map(['a','b','c'], in_processes: 3) { |one_letter| ... }
# 3 Threads -> finished after 1 run
results = Parallel.map(['a','b','c'], in_threads: 3) { |one_letter| ... }
つっつきボイス:「parallelっていうgemは見たことありそうでなかったので」「このgemは前からありそうな雰囲気ですけど既に標準だったりしません?」「標準ライブラリのリストにはありませんでした」
後で調べると、parallel gemは2009年からありました。
「Rubyで並列的なことをやる方法って他にもいろいろありそうですけど?」「標準ライブラリにThreadとかFiberとかありますね↓😋」「なるほど」
参考: class Thread
(Ruby 2.6.0)
参考: class Fiber
(Ruby 2.6.0)
「そういえばちょっと前のQuoraで『現状のThreadは直したい』というMatzからの回答↓があったのを思い出しました」「並列系って自分もそもそもほとんどやってこなかったし、ちゃんと勉強してからやらないときっとハマりそう😭」「私もGo言語のgoroutimeまだ自分ではやれてないです😅」
参考: Rubyを作り直すとしたら、変更を加える箇所はありますか? - Quora
「Active Recordでもやれるようです↓」「これでテストを速くできるならいいかも😋」「parallel gemのコントリビューターもめちゃ多いですね😳」
# reproducibly fixes things (spec/cases/map_with_ar.rb)
Parallel.each(User.all, in_processes: 8) do |user|
user.update_attribute(:some_attribute, some_value)
end
User.connection.reconnect!
# maybe helps: explicitly use connection pool
Parallel.each(User.all, in_threads: 8) do |user|
ActiveRecord::Base.connection_pool.with_connection do
user.update_attribute(:some_attribute, some_value)
end
end
# maybe helps: reconnect once inside every fork
Parallel.each(User.all, in_processes: 8) do |user|
@reconnected ||= User.connection.reconnect! || true
user.update_attribute(:some_attribute, some_value)
end
後で調べると、同じ作者のparallel_testsというgem↓はだいぶ前にウォッチで取り上げたことがありました(ウォッチ20171117)。gemspecでもparallel gemがruntime dependencyになっています。
⚓その他Ruby
- イベント: Agenda Londond Ruby Unconference 2019(Ruby Weeklyより)
- イベント: RubyConf 2019 -- 米国ナッシュビルにて
素晴らしい洞察力。私は当初だいぶ不安だったなあ。 https://t.co/msi2XU2Osa
— Yukihiro Matsumoto (@yukihiro_matz) October 16, 2019
つっつきボイス:「川合史朗さんはScheme系言語のGaucheの作者ですね」「ガウシュ?ゴーシュ?😆」「セロ弾きのゴーシュとスペル同じですしゴーシュなのかも🤔」「この方はハワイ在住で俳優もやっていて、いくつか映画にも出演してるそうです🏝」「ソフトウェア開発者で俳優...なんと幸せな人生😊」
参考: Gauche - Wikipedia
参考: 17. Gauche Schemeの基本デザインの選択理由、オブジェクトデータベース、浮動小数点数の落とし穴 (川合史朗) -- 映画出演の話にも触れられています
⚓DB
⚓Oracleから独自RDBへ
- 元記事: アリババの独自開発DB、オラクル抜き世界一に 20人の部隊から
- 元記事: AWS、Amazon PrimeやKindle、Alexaなどで使用していた約75ペタバイト7500のOracleデータベースをダウンタイムなしで自社データベースサービスへ移行したと報告 - Publickey(Publickeyより)
つっつきボイス:「Oracleから自社製RDBMSへの乗り換えニュースを2つ連続で見かけました」「これスゴいですよね〜、自社製のRDBMSがどんなものか触ってみたい気がしますけど」「お、アリババの方はソース公開されてるって記事にありますね😳」「お〜、このoceanbaseというのがそれですか↓: 誰か動かしてみないかな😋」「Amazonの方は名前もわからず😢」
ちなみにoceanbaseのドキュメントは中国語かつdocxのようです😭。
「oceanbaseについて探してたら、dbdb.io↓というサイトが出てきた」「いろんなRDBMSを一覧できるカタログサイトのようですね☺️」
以下はつっつき後に見つけました。
参考: 世界1位になったアリババの独自開発DB OceanBaseとは何者か? - ブログなんだよもん
⚓言語・ツール
⚓言語人気の移り変わり
Most Popular Programming Languages 1965 - 2019 pic.twitter.com/NNuLHr2FqI
— Rich Rogers (@RichRogers_) October 14, 2019
つっつきボイス:「こういうのって単純に楽しいですね😊」「どこ由来のデータかは知りませんけど😆」「大昔はFortranとCobolが人気だったまではわかるんですが、Pascalが1位だった時代ってあったんですか?」「Mac OS 9までのMacだとTurbo Pascalが割と多かった気がします」「そうこうしているうちにC言語トップになって2000年過ぎたあたりからJavaが1位に」「PHP元気だな〜😆」「Rubyもトップテンに」「直近はPythonがトップ」
⚓その他
⚓キーボードの方がでかい
"Type-CポートによるUSB PD動作にも対応。DisplayPort Alt-modeもサポートするため、USB PD給電対応ディスプレイと組み合わせれば、Type-Cケーブル1本で利用できる" しゅごい / “【PC短評】ケーブル1本で動く極小デスクトップ、レノボ「ThinkCentre M90n-1 Nano」 - PC Watch” https://t.co/yk3A4mRuaC
— Mitsuru SHIMAMURA (@smbd) October 16, 2019
つっつきボイス:「ぱっと見Wi-Fiアンテナ付きダムハブみたいですけど😆」「あ、これPCですか😳: このスペック(Core i7-8665U 1.9GHz、メモリ16GB)で18万...やばい猛烈に欲しくなってきた❤️」「ハートに突き刺さる音が聞こえました😆」「NASつないじゃえば容量問題にならないし、う〜こっち買えばよかったか😭」「もう少しスペック下でもいいから軽くて安いのがあればDocker専用機にして持ち歩きたい😆」(以下延々)
⚓番外
⚓自然言語も移り変わる
濁音の前に軽いンのような音が入るのは「入り渡り鼻音」と呼ばれるものですが、16世紀には衰退が始まっていました。
特にバ行は最も早く衰退し、16世紀半ばでも消えかけていたようなので、信長や秀吉の発音にあったのかやや微妙なところです。
ダ行は16世紀末期でも残っていたようです。— LingLang@言語学好き (@linglanglong) October 15, 2019
語中のガ行は[ᵑɡ]のように鼻音+破裂音だったと考えられています。
これと同様の発音は新潟の下越、山形の村山地方、高知、和歌山や徳島の山間部などに見られます。
これが[ŋ]になったのがガ行鼻濁音で、東京でも一般的でしたが衰退傾向です。
鼻音性を完全に失った[ɡ]も広く分布します。— LingLang@言語学好き (@linglanglong) October 15, 2019
つっつきボイス:「最後は言語学ネタで😆: 羽柴秀吉がファシンバ・フィンデヨシだったとか」「何を基準にしてたのかしら😅」「安土桃山時代のポルトガル人宣教師たちが作った日本語-ポルトガル語辞書で当時の発音がキャプチャされてたそうで、は行がɸ音(ph)だったとかかなり違ってますね」「ほぇ〜😳」「ついでに、日本語の濁点や半濁点も、その宣教師たちが必要に迫られてこしらえたのが後に日本語でも定着しちゃったんだそうです」「逆輸入😆」
参考: 日葡辞書 - Wikipedia
「そうなるとポルトガル人の発音も今と昔で違ってるでしょうから、そういうフィルタの影響を取り除いて研究するのは大変そう😆」「たしかに😆」「日本人もかつてイギリスをエゲレスとかアメリカンをメリケンとか言ってましたし、外人が日本人の名前を呼ぶときに訛るのと似てるようにも見えますけどね😆」「英語圏の人は『こんにちは』を『コニーチワ』って発音しがちですけど、その辺に通じるかも」「n音が連続するとつながるんでしょうね☺️」(以下延々)
江戸時代の長崎出島の通詞(=通訳)が幕末にオランダに渡ったとき、現地の人から「まるでうちのおじいさんが話しているようなオランダ語だ」と妙に感激されたという話を思い出しました。鎖国のせいでタイムカプセル的に保存されてたんでしょうね。
例えば「法」という漢字は歴史的仮名遣で「ほふ」ですが、日本伝来当初は [pop]と発音されていました。
それが
[pop] > [popu]~[ɸop]> [ɸoɸu] (フォフ) > [ɸou] > [ɸoː] > [hoː]
と変化して現代に至ります。— LingLang@言語学好き (@linglanglong) October 16, 2019
「自然言語もこんなに変わるんだからプログラミング言語も長年の間にがらっと変わったりするかなと」「いやいやプログラミング言語は発音関係ありませんから😆」
今回は以上です。
おたより発掘
あーArray#unionいいなあ。Set(x).to_a 置き換えられてうれしい。
ActiveRecordへSet渡すとArrayと微妙に挙動変わるんだよね……週刊Railsウォッチ(20191021) https://t.co/JxFrKCA8Fi
— Jaga Apple (@jagaapple_tech) October 22, 2019
https://t.co/GGC3sLqkQy
rails/railsでも「r?」記法が使われてるのか。もしかしたらrust-lang/rustが由来じゃないかと思ってる。bors(rust-lang/rustで使われてるマージボット)にr+記法というのがあるので— Masaki Hara (@qnighy) October 21, 2019
バックナンバー(2019年度第4四半期)
- 20191008後編 Ruby 2.7のInteger#[]でバイナリチェック、rubyzip gemは強力、13KBのJavaScriptゲームほか
- 20191001後編 RedisとRubyをつなぐredis-object gem、Fullstaq Rubyの新バージョン、COUNT(*)とCOUNT(1)の速度ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp Slackなど)です。