電柱商事

CHANGELOG v0.28.0

2019/04/17

[原文]

言語仕様

(破壊的変更) Enum の定義内でメンバーの区切りに空白文字を使用できなくなり、改行文字、;, だけが使用可能になった。ただし、, の使用は非推奨であり、フォーマッタによって ; に置き換えられる(#7607#7618

原文では、, は改行文字に置き換えられるとなっているが、ソースの変更内容を見る限り ; に置き換わるっぽい。(brew版が来ていないので未確認)

開始条件や終了条件のない範囲オブジェクト(例:array[5..])を生成可能に(#7179

配列のある要素から後ろ全部が欲しい時に array[5..-1] みたいな不自然な指定をしなくてもよくなった。

offsetof(Type, @ivar) 構文を追加(#7589

その型がメモリに格納される際に指定したインスタンス変数が使用するメモリ番地のオフセットを返す。一部のCライブラリで必要になるらしい。

マクロ

指定された型の注釈(anotation)全てを取得するための Type#annotations を追加。(#7326

これまでにも注釈を取得する Type#annotation があったものの、指定された型の注釈が複数あった場合に、最後に指定されたものしか取得できなかった。

ArrayLiteral#sort_by を追加(#3947

Array#sort_by と同様の操作を、マクロ内の ArrayLiteral オブジェクトに対しても実行可能に。

標準ライブラリ

(破壊的変更) フラグ注釈された Enum 型で、Enum.from_valueを使って None を生成できるようになった(#6516

フラグ注釈された Enum (※)として定義された F 型で、F.from_value 0 を実行すると、これまで例外を返していたが、この変更によって F::None を返すようになった。

※: @[Flags] 注釈付きで Emun を定義すると、Enum の各メンバーをビットフラグのように扱って複数のフラグの重ね合わせを表現できるようになる。フラグ値が 0 ならどのフラグも立っていない状態(None)になって然るべき

(破壊的変更) PartialComparable に非推奨である旨の注釈を追加(#7664

その機能は Comparable に統合されているとのこと。

(性能改善) DWARF 形式デバッグ情報の行番号デコードを最適化(#7413

Signal::CHLD.reset が以前のハンドラをクリアできていなかったのを修正(#7409

Object.getter? マクロ と Object.property? マクロの lazy 版を追加(#7322

getterproperty にブロックを指定すると、ゲッタメソッドを初めて呼び出したタイミングでブロックを評価した結果でインスタンス変数が初期化される。その仕組みが、getter?property? にも追加された。

ゲッタメソッドが呼び出された時点で、インスタンス変数が nilだった場合に、ブロックが評価されるような実装になっているので、property?(a : Int32) { 0 } などのようにブロックで初期値を与えると、明示的に foo.a = nilnil を代入したとしても、次回 foo.a を呼ぶと 0 が返される。

Comparable#<=> の返り値として、-101 以外の値も許容するようにした(#7277

#<=> の比較を、数値の大小で比較するような場合に

def param : Int32
  #...
end

def <=>(other : self)
  self.param - other.param
end

と書けるようになって非常に楽。

API ドキュメントのサンプルコードに欠けていた require 文を追加(#7564

複数箇所のサンプルコードを修正 (#7569, thanks @maiha)

実行するとエラーになったり、実際の出力と齟齬があるサンプルコードなどが多数修正された。

Bool 型のドキュメントを追加(#7651

GLIBC_PRIVATEシンボルであるスレッドローカルな $errno の使用を避けるよう改修(#7496

標準ライブラリ内の #to_s#inspect が全て同じ型定義を持つよう修正(#7528

#to_s はオブジェクトの文字列表現(String型)を返す。文字列表現の定義は #to_s(io :IO) で、引数として与えられた IO オブジェクトに書き込むことで行う。p foo などで使用される #inspect#inspect(io : IO) の関係も同じ。

これらの定義が、標準ライブラリを通じて def to_s : Stringdef to_s(io : IO) : Nildef inspect : Stringdef inspect(io : IO) : Nilに統一された。自作の型でもこれに倣うのが吉。

数値

(破壊的変更) Int#/ が v0.29.0 からは Float 型の結果を返すようになるため、整数として除算結果を取得したい場合は Int#// を使用するようにとのメッセージを追加(#7639

Number#inspect が型を明示しないように修正(#7525

v0.24.0 で行われた修正が撤回された形。

Int#leading_zeros_countInt#trailing_zeros_count を追加(#7520

それぞれ、数値を2進数表記した際に先頭並ぶ0の数と末尾に並ぶ0の数を返す。

a = "00001000".to_i8(base : 2)
#=> 8

a.leading_zeros_count
#=> 4

a.trailing_zeros_count
#=> 3

ただし、BigInt に関しては、#leading_zeros_count が実装されていない。可変長の整数に対しては #leading_zeros_count 特定できないため。

Big* 系の数値型に欠けていた各種メソッドを追加(#7638

#floor#ceil#trunc#//や、BigInt に対する &(+|-|*|**) 演算子など。

OverflowError のメッセージを改善(#7375

テキスト

(性能改善) 文字列がASCII文字しか含まない場合の String#compare の処理を改善(#7352

数値を人間が読みやすい形式にする Number#formatNumber#humanizeInt#humanize_bytes メソッドを追加(#6314

lsdf コマンドに -h オプションをつけた時のように、大きなもしくは小さな数値を KG といった単位をつけて読みやすくしてくれるっぽい。

バイトに関しては、10の3乗を基準とするSI系接頭辞(KBGBTBなど)と、2の10乗(1024)を基準とするIEC系接頭辞(KiBGiBTiBなど)を選択可能。

String#rchop?String#lchop? を追加(#7328

文字列の末尾や先頭から引数として与えられた文字列(文字)を削除する#rchop#lchopは、指定された端が引数にマッチしなかった場合にレシーバ文字列をそのまま返すが、こちらは実際に削除が行われた場合のみ削除後の文字列を返し、そうでない場合は nil を返す。

String#camelcaseString#underscoreoptions 引数を追加(#7374

次項の Unicode::CaseOptions を指定できる。

Unicode::CaseOptions のドキュメント追加(#7513

テュルク語など、特有の大文字小文字変換規則をもった言語対応のためのオプション。

String#each_lineIO#each_line のドキュメントとスペックを改善 (#7419

コレクション

(破壊的変更) Array#sort#<=> メソッドだけを使用するようなり、部分的に比較可能な場合に #<=>nil を返せるようにした(#6611

このPRだけでいくつかの変更が行われている。

  1. これまで #<#<= を使用していた Array#sort の実装が、ドキュメント通り、#<=> だけを使用するように変更された。
  2. ComparablePartialComparable が機能的に統語され、#<=>nil を返せるようになった。通常、返り値 nil は2つのオブジェクトの型を比較できない場合に使用される。一方、2つのオブジェクトが同じ型な場合も、通常比較可能であるが、例外的に比較できないような場合(PartialComparable)にも利用できる。例としては Float 同士の比較(原則比較可能だが、NaN が絡むと比較できなくなる)など。
  3. Array#sort と関連したメソッドで #<=>nil を返した際の処理が追加され、そうした場合は例外を発するようになった。
  4. Number <=> NumberNaN が絡んだ場合に nil を返すが、Int <=> Intnil を返すことがないよう最適化された。

(破壊的変更) Iterator#rewind をなくして #cycle を実装(#7440

これまで、Iterator モジュールにはイテレータのインデックスを先頭に戻す #rewind が抽象メソッドとして定義されていて、Iterator を mix-in しようとする型はそれぞれに #rewind 実装しなければならなかった。

ただ、Iterator であっても #rewind の利用が想定されない場合もあり、また #rewind を使うにしても、最後の要素まで到達した際に先頭へ戻る用途でしか使われない場合も多い。

そのため、Iterator から #rewind の定義が取り除かれ、代わりに #cycle が実装された。#cycle は要素を内部配列として保持することで、終端まで到達した後、先頭へ戻ることが可能なイテレータオブジェクトを返す。

a = [0,1,2]

cycled_s = a.each.cycle
cycled_s.next => 0
cycled_s.next => 1
cycled_s.next => 2
cycled_s.next => 0
cycled_s.next => 1
# ....

このことにより、Iterator 利用時に個別の #rewind を定義する必要がなくなり、標準ライブラリの各所からコードがかなり削減されている。

なお、バッファIO周りの #rewind は個別に残されているので、ファイルの読み込み中にオフセットを先頭に戻すような利用は可能。

(性能改善) Enumerable#each_cons で再利用バッファに Dequeも使えるようにした(#7233

これまでは reuse 引数で指定する再利用バッファとして Array オブジェクトしか指定できなかったが、Deque オブジェクトも利用できるようになった(DequeArray 比べて先頭や末尾への追加/削除のパフォーマンスが高いので恩恵を受けられそう)

Iterator#cons も同じ形式で Deque オブジェクトを指定できるようになっている。

(性能改善) Range#bsearch 内の / 2>> 1 へ変更することで高速化(#7531

LLVMの仕様上、符号付き整数の割り算はビットシフトと比べるとパフォーマンスがよろしくないらしい。

要素の型がプリミティブ型でない場合の Slice#clone の挙動を修正し、深いコピーを行うように(#7591

これまでは、プリミティブな型(固定長の数値型)以外を要素として持つスライスだと #clone 実行時にエラーが出ていた。

ついでに(?)、#clone が深いコピーの結果を返す(各要素に対して #clone を呼ぶ)ように修正されている。ちなみに、#dup が浅いコピー。(おそらく、要素の型が #clone を実装していないとエラーになると思われる。未検証)

Indexable#zipIndexable#zip?Enumerable へ移動し、引数として IndexableIterableIterator オブジェクトを幾つでも指定できるようにした(#7453

プルリクエストのサンプルコードを見てると色々できそう。

Slice#[](Range) を追加(#7439

ArrayString に該当する要素がまったくなかった際に nil を返す #[]?(Range) を追加(#7338

Set#add? を追加(#7495

引数として渡されたオブジェクトが実際に追加されたら true を、すでに同じ値を持っていて状態が変かしなかったら false を返す。

要素の順序に関する Hash のドキュメントを改善(#7594

シリアライズ

(破壊的変更) YAML#libyaml_version の返り値の型を SemanticVersion へ変更(#7555

バージョンの大小関係を SemanticVersion 型でチェックするようになった。普通に使ってる分にはあまり影響はないかと。

libxml2 2.9.9 のサポートを修正(#7477

libyaml 0.2.2 のサポートを修正(#7555

BigDecimal.from_yaml を追加(#7398

時刻/時間

(破壊的変更) Time 型のコンストラクタ名を変更。Time.now は非推奨となり、Time.utc もしくは Time.local の使用を推奨(#5346#7586

(破壊的変更) 日数やその他の単位で時刻を変更する Time#add_span の名前を Time#shift へ変更(#6598

(破壊的変更) Time#dateTuple{year, month, day})を返すよう変更。(#5822

これまでのように Time オブジェクトが必要な場合は、Time#at_beginning_of_day を使う。

Windows でのモノトニック時刻に関するバグを修正(#7377

Time 型のメソッドを改善(#6581

年、月、日を与えると、西暦1年1月1日からの経過日数を返してくれる Time.absolute_days と、現在時刻から年、月、日、および年内の通算日数を返してくれる Time#year_month_day_day_year(共に protected メソッド)の内部処理が改善された。

ファイル

(破壊的変更) IO#flush_on_newline を廃止、TTYデバイスの時も sync を使う(#7470

Path 型を追加(#5635

Ruby の Pathname クラスのような、ファイルパスを操作する型ができた。

ネットワーク

(破壊的変更) HTTP::MultipartMIME::Multipart に変更(#7085

(破壊的変更) OAuth2エラー字のJSONパースを廃止(#7467

(破壊的変更) RequestProcessor の再利用ロジックを修正(#7055

(破壊的変更) HTTP.default_status_message_for(Int)HTTP::Status.new(Int).description で置き換え(#7247

(破壊的変更) URI の実装上の問題を修正(#6323, thanks @straight-shoota)

URI#opaque メソッドは URI#path に統合し、Nil を返さないように。

#parse/#to_s の正規化とデフォルトポートの扱いを変更。

OpenSSL ソケットへの書き込みバッファ処理を修正(#7460

HTTP::Server#bind_*内のメモリリークを修正(#7197

IO の閉じ忘れ。

HTTP::Request#remote_address を追加(#7610

HTTP::StatusResponse#status を追加(#7247#7682

OAuth 2.0 のリソースオーナーパスワードに対応(#7424

クッキー内のIISの日付形式に対応(#7405

IO::Syscall#wait_readableIO::Syscall#wait_writableを許可(#7366

HTTP::Client のスペックを、タイムアウト後にサーバレスポンスを書かないよう変更(#7402

musl 向けに TCP::Server のスペックを修正(#7484

暗号化

(破壊的変更) OpenSSL::HMACdigest/hexdigest におけるアルゴリズム指定に、シンボルではなく OpenSSL::Algorithm 型を使用するよう変更し、LibCrypt の PKCS5_PBKDF2_HMAC メソッドに対応(#7264

並行処理

マルチスレッド対応GCを追加(#7546

-D preview_mt 付きでコンパイルすると利用可能。

bdw-gc にマルチスレッド対応パッチを適用(#7622

Fiber::StackPoolFiber から独立させるよう改修(#7417

IO::SyscallIO::Evented として改修(#7505

システム

execvp エラーメッセージにコマンド名と引数を追加(#7511

ファイバ内のシグナル処理を改修(#7469

Spec

スペックの実行中に CTRL+C で中断する際の処理を改善(#7426

各スペックの前に Fiber.yield を実行して、シグナル処理するタイミングを設けている。これがないと、IOウェイトなどが発生して処理ファイバが切り替わるタイミングまで中断できない。

マルチスレッドに対応すれば不要になるだろう、とのこと。

pendingit の引数に定数を指定できるよう修正(#7646

コンパイラ

(性能改善) --threads=1 が指定された際に fork や spawn をしないよう変更(#7397

require ファイルが存在しない場合に投げられる例外を修正(#7386

多重代入で代入先に定数があった場合のコンパイラ内部エラーを修正(#7468

->foo.[] やその他演算子のパースや挙動を修正(#7334

asm のパースで3連続コロン(:)と変数が指定された際の処理を修正(#7627

オフセットインデックスが更新されずに無限ループに陥っていた模様。

非推奨な(@[Deprecated] が付けられた)メソッドの使用に警告を出すようにするオプトインのコンパイルフラグを追加(#7596#7626#7661

静的ライブラリの検索先に CRYSTAL_LIBRARY_PATH を追加(#7562

未定義のメソッドや変数を使用しようとした際のエラーメッセージに、スコープ(with ... yield スコープを含む)を表示するよう改善(#7384

yield で実行されるブロックから break しようとした際に、エラーメッセージ中で next を使用するよう提示するようにした(#7406

コンパイラコンフィグでLinux 環境を取得できるようにした(#7479

残っていた //& 演算子への対応(#7628

Crystal::Config.versionread_file マクロを使用するよう改修(#7081

マクロのスペックを外部コマンドを実行しないよう書き直し(#6962

内部的なtypoを修正(#7592

セマンティクス

as/as? とユニオン型に由来するいくつかの問題を修正(#7475

同名のメソッドに、インスタンス化されていないジェネリック型(Foo)を引数とする定義と、インスタンス化されたジェネリック型(Foo(Int32))を引数とする定義がった場合に、正しくメソッドが選択されるようにした(#7537

def foo(a : Foo)
end

def foo(a : Foo(Int32))
end

みたいな時に、Foo(Int32) 型の引数が後者のメソッドへ渡されるようになった。

同名のメソッドに、明示的に指定した型を引数とする定義と、フリー変数で指定した型を引数とする定義があった場合に、正しくメソッドが選択されるようにした(#7536#7580

def foo(a : T.class) forall T
end

def foo(a : Int32.class)
end

みたいな時に、foo(Int32) が後者のメソッドへを呼ぶようになった。

def foo(a : T) forall T
end

def foo(a : Array(T)) forall T
end

みたいな時も、Array(Int32) 型の引数が後者のメソッドへ渡されるようになっている。

initializeprotected として宣言された場合に、newprotected として定義されるようにした(#7510

名前付き引数の型マッチングを修正(#7529

Proc 型のマッチングが、返り値の型に対して寛容になった(#7527

これまでは、以下のようなコードがエラーになっていた。

class Foo
  @bar : Proc(String, Nil)
  @bar = ->(a : String) { 1 }
end

@bar は文字列を引数に取り、なにがしかの操作をするが返り値を必要としないことを明示した Proc 型。一方、代入した Proc オブジェクトは、ブロック内の最後の式の評価が 1 なため、コンパイラからは Proc(String, Int32) 型に見えてしまう。

今回の変更により、返り値が Nil 型である Proc 型は、引数の型が同じであれば、ブロックの評価結果が何型であろうと受け入れられるようになった。

言い換えれば、コンパイラは Proc 型の返り値には頓着しない、という実装になっている。

Proc に対する再帰的なエイリアス指定のパース処理を修正(#7568

Tools

travis.yml 内でユーザに対してフォーマッタを実行するよう提案(#7138

ただしデフォルトはコメントアウト状態。

フォーマッタ

1\n.as(Int32)のフォーマッティングを修正(#7347

ネストした配列要素のフォーマッティングを修正(#7450

Enum とコメントのフォーマッティングを修正(#7605

フォーマッティング対象を絶対パスDe指定した際のCLI処理を修正(#7560

ドキュメント生成

private な定数を含まないように修正(#7575

Crystal に内蔵された定数が含まれるよう修正(#7623

crystal docs コマンド用のコンパイルフラグを追加(#6668#7438

@[Deprecated] 注釈が付いている場合に Deprecated タグを表示するようにした(#7653

Playground

可読性を上げるためのフォントウェイトの変更(#7552

その他

CIの強化と掃除(#7359#7381#7388#7387#7390#7622

最近の Docker イメージで使用する 64bit Linux版パッケージのスモークテスト(#7389

git の pre-commit hook について CONTRIBUTING.md で言及(#7617

ソースコードの各所でスペルミスを修正(#7361

ソースコードの各所で String リテラルの代わりに Char リテラルを使用(#6237

1文字のリテラルであれば Char リテラルの方がパフォーマンスが良い。

Thread のスペック内で GC の終了処理に関するワーニングを修正(#7403

Linux 用配布パッケージにHTML形式のAPIドキュメントが含まれていたのを削除(#7519