単項マイナスと構文解析
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合
Rubyの演算子とその再定義について書きます。
Rubyのドキュメントによると、次のような演算子があります。 表の「意味」は正確ではなく「およそ」「良く用いられる場合」についての説明です。
優先度 | 演算子 | 意味 |
---|---|---|
高い | :: |
「クラス::定数」など |
[] |
配列参照など | |
+ (単項演算子) ! ~ |
正符号、論理否定、ビット反転 | |
** |
累乗 | |
- (単項演算子) |
負符号 | |
* / % |
積、商、剰余 | |
+ - |
和、差 | |
<< >> |
ビットシフト、追加 | |
& |
ビット積 | |
| ^ |
ビット和、排他的論理和 | |
> >= < <= |
大小比較 | |
<=> == === != =~ !~ |
比較、等、不等 | |
&& |
論理積「かつ」 | |
|| |
論理和「または」 | |
.. ... |
範囲 | |
?: |
条件演算子、三項演算子 | |
= (+= , -= など) |
代入(自己代入) | |
not |
論理否定 | |
低い | and or |
論理積、和 |
これらの演算子のうち一部は糖衣構文によってメソッドに置き換えられます。 ということはそれらの演算子はオブジェクトごとに定義されているので、様々な意味付けがありえます。 表の中の「意味」はよく使われるオブジェクトに対する「意味」です。
ここで、糖衣構文(シンタックス・シュガー)について少し詳しく見てみます。
プログラムの中で
a == b
が出てきたとします。
aとbは変数で、何らかのオブジェクトを指しています。
つまりオブジェクト == オブジェクト
の形です。
このとき、この構文は次の構文と同じだとRubyが判断します。
a.==(b)
これはオブジェクトaの==
メソッドを引数bをつけて呼び出すことに他なりません。
ですから、二項演算子==
は実は左辺のオブジェクトのメソッド(メソッド名)になります。
その意味はオブジェクトごとに決まっています。
概念的には「等しい」ですが、オブジェクトごとに「等しい」の具体的な内容は異なっているわけです。
==
メソッドの結果が等しくなっているまた、違う種類のオブジェクトを==
で比較すると、大抵の場合は「等しくない」という結果になります。
しかし、絶対異なるというわけでもなく、1.0==1
は実数と整数という異なるオブジェクト間の比較ですがtrueになります。
これは、実数の==
の定義の中で、引数が整数の場合はそれを実数に変換するなどの比較可能な形にして調べているからです(実装を確認したわけではない)。
代入=
はメソッドではなく、再定義できません。
なぜなら、代入の左辺はオブジェクトではなく、変数だからです。
変数自身にはメソッドはありません。
a = 10
a = "abc"
1行目は変数aに整数10を代入しています。 2行目の左辺aは整数オブジェクト10を指してはいますが、代入先はそのオブジェクトではなく、変数a自身です。 aはオブジェクト10から切り離されて、新たに文字列オブジェクト”abc”を指すようになります。
これと似ていますが、次のプログラムは意味が異なります。
a.x = 10
a.x
は変数ではありません。
変数a
の指すオブジェクトのxメソッドの返した値になります。
ですから、この文では=
が代入のイコールだとするとエラーになるはずです(代入はオブジェクトにはできない)。
しかし、エラーにならないこともあるのです。
それはオブジェクトにx=
というメソッドが定義されている場合です。
この文は糖衣構文で次のように置き換えられます。
a.x=(10)
元の式ではa.x
と=
の間に半角空白があったのですが、糖衣構文の適用でこの空白は消えてしまいます。
a.x
ではなくa.x=
がひとまとまりです。
一般に空白は区切りを表しますが、これは例外ということになります。
左辺のオブジェクトにx=
メソッドが定義されていなければエラーになり、つぎのようなメッセージが現れます。
undefined method `x=' for (左辺のオブジェクト)
エラーの内容は「x=
メソッドが左辺のオブジェクトにない」です。
このことからも、糖衣構文の置き換えが行われた後にエラーが発生したことがわかります。
次の演算子は再定義することができます。 再定義はオブジェクトのメソッドとして行います。
| ^ & <=> == === =~ > >= < <= << >>
+ - * / % ** ~ +@ -@ [] []= ` ! != !~
+@
と-@
は単行演算子の+
と-
を表します。
メソッド定義をする場合はアットマークをつけた名前を使います。
これらの演算子の意味は、それぞれのオブジェクトのメソッドで確認します。
例えば、<<
については各オブジェクトで次のような意味で使われます。
演算子そのものには確定した意味がないことに注意してください。 演算子の意味を決めるのは各オブジェクトのメソッド定義です。
逆に再定義できない演算子は
= (自己代入) ?: .. ... not && and || or ::
です。
=
は再定義できませんが、data=
のようにメソッド名の最後につけることは可能です。
これらの再定義できない演算子は言語の制御構造で使われます。 これらの演算子も使い方が一通りでない場合があります。 ドキュメントでは一箇所に演算子の意味をまとめて書いているのではなく、それぞれのトピックの中で説明されています。 つまりドキュメントのあちこちにばらばらに書かれています。
ここでは、2次元ベクトルのクラスを定義して、和と差を再定義してみましょう。
class Vec
def initialize(x=0, y=0)
@x = x
@y = y
end
def x
@x
end
def y
@y
end
def +(other)
Vec.new(@x+other.x, @y+other.y)
end
def -(other)
Vec.new(@x-other.x, @y-other.y)
end
def to_s
"(#{@x}, #{@y})"
end
end
a = Vec.new(1,2)
b = Vec.new(-2,4)
print "#{a} + #{b} = #{a+b}\n"
print "#{a} - #{b} = #{a-b}\n"
Vecは2次元ベクトルを表すクラスです。 x成分、y成分をそれぞれ@x、@yのインスタンス変数に保持します。 このオブジェクトは一度生成された後は値を変えないことにしています。 このような変更不可のオブジェクトはイミュータブル(immutable)といいます。 変更可能はミュータブル(mutable)です。
オブジェクトを生成する時に、引数をつけます。 引数によってベクトルの各成分が決まります。
メソッドは、各成分を返す、和と差を計算して新たなVecオブジェクトを返す、オブジェクトを文字列にする、です。
演算子+と-を再定義しています。 この再定義のメソッドでは、otherというパラメータが演算の相手方を表しています。 otherはVecオブジェクトを想定しています。 それ以外のオブジェクトを引数にしてメソッドが呼ばれたときの対策ないので、エラーが起こります。 本当はその対策が必要ですが、ここではあくまで例ですので単純化しました。
to_sメソッドは文字列の式展開の中で(背後で)使われます。 もしこのメソッドを定義してなければ、式展開の結果が恐ろしいものになってしまうでしょう。
実行してみます。
(1, 2) + (-2, 4) = (-1, 6)
(1, 2) - (-2, 4) = (3, -2)
きちんと計算できていることがわかります。
演算子、とくに四則計算の演算子は数学用ですので、その他のオブジェクトを定義するときにはあまり使われないかもしれません。 しかし、文字列結合に+が用いられているように、演算子がそのメソッドのイメージに合うこともあるでしょう。 そのときには、ぜひ再定義してみてください。
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合
パーサ・ジェネレータとは 少し複雑な文法 四則(加減乗除)計算のBNF Racc で実装 クラス定義、BNFの記述部分 ヘッダー、インナー、フッター コンパイルと実行 演算子の優先順位と結合における左右の優先順位 まとめ
StrScanライブラリのドキュメント 字句解析とは StrScanライブラリ StrScanライブラリを使った字句解析 実例
lbtというgemを作って公開してみた lbtはどんなgemか ファイルの配置 lbt.gemspec Rakefile gemのビルド RubyGems.orgへのアップロード 補足・・rake/gempackagetaskサブライブラリについて
文字列のエンコーディングに頭を悩ませることはほとんどなくなりました。 なぜなら、どのアプリ、システムもUTF-8を使うようになったからです。 Rubyでもエンコーディングの問題が起こることはまず無いでしょう。 ですが、今回はエンコーディングの考え方を整理してみたいと思います。
Fiberを書いたときから、次はスレッドを書こうと思っていましたが、時間がかかってしまいました。 その理由は、期待したとおりのスレッドの効果がなかったためです。 今回はそのことを書きますが、これはRubyのスレッドの抱えている問題なのか、自分のやり方が悪いのかははっきりしていません。
Fiberは「ノンプリエンプティブな軽量スレッド」とRubyのマニュアルに記載されています。
今回はRubyプログラムから自動的にドキュメントを作成するRDocについて書きたいと思います。 私はこのことについて、エキスパートではありません。 この記事も、初心者の体験談だと考えてください。
Ruby/Gtkの記事を先日書いたときに、「これはかなり使える」という手応えを感じたので、WordBook(Railsで作った単語帳プログラム)のGTK 4版を作りました。 プログラムは「徒然なるままにRuby」のGitHubレポジトリに置いてあります。 レポジトリをダウンロードし、ディレクトリ_example/...
今回はGTK 3とGTK 4をRubyで使うライブラリについて書きたいと思います。
今回もRubyとGUIのトピックです。 Glimmerを取り上げます。
Rubyはグラフィックについて弱い印象があります。 しかし、グラフィックはデバイスに関することなので、言語そのものには直接の関係はないはずで、あるとすればライブラリです。 今後グラフィック関係のgemが開発されることに期待しましょう。
Rails7におけるシステムテストについて書きます。
前回作ったWordbook(リソースフル)のテストを書いてみます。 RailsのテストはminitestをRails用に拡張したものです。
今回はRailsの慣例に沿った形でWordbookを作り直します。
今回はWordBookの検索と削除についてです。
今回はRailsにおけるデータの作成と保存、そして変更について説明します。 そのベースになるモデルとデータベースの話から始め、appendとchangeの動作について詳しく説明します。
一般に、HTMLは文書の構造を表し、CSSはその体裁(見栄え)を表します。 Railsは最終的にCSSを含むHTML文書を出力するので、この2つについての理解が必須です。 この記事ではとくにCSSの人気ライブラリであるBootstrapを紹介します。 BootstrapはJavascriptも含んでいます。
Rubyの最も人気のあるアプリケーションであるRuby on Railsを取り上げようと思い、書き始めました。 予想してはいましたが、相当な分量になってしまいました。 そのため、何回かに分けて記事にすることにします。 また、対象となる読者のレベルをどうしようかと考えましたが、「徒然Ruby」が基礎的な内容から始ま...
Rubyのライブラリ管理システムのRubygemsとコマンドgemおよびbundlerについて説明します。
minitestについて連続して2回書いてきました。 「minitestはドキュメントが少ない」という人がいますが、私も同感です。 例えば、モックとスタブの説明も少ないです。 そこで、今回はmock.rbのソースコードを参考に、モックの私的ドキュメントを書いてみました。 あくまで私個人の考えであり、minites...
今回もminitestの話です。 mockとstubに焦点をあて説明します。
アプリ作成の記事でminitestを使いました。 今回はminitestについて、また一般にテストについて、私の考えを書こうと思います。
今回はメソッドの呼び出し制限ついて説明します。 呼び出し制限にはpublic、private、protectedの3つがあります。
今回は特異メソッド、特異クラス定義、名前空間、モジュール関数について説明します。
2023/10/29 追記:この記事は新しく書き直しました。 古い記事で使っていたGitHubのCalcが大幅にアップデートされたためです。 そこで、この記事に合うようなプログラムsimple_calcを新たに作りました。 このプログラムは本レポジトリの_example/simple_calcにあります。
if〜elsif〜・・・〜else〜endは皆さん良く使うでしょうか? これは場合分けで良く使われる方法です。 これと同様の制御構造にcase文があります。 Cのswitch文に似ていますが、より強力な機能を持っています。 if-else-endよりも高い能力があるといえます。
Procオブジェクトを生成するメソッドlambdaについて説明します。
今回はブロックを一般化したオブジェクトProcを説明します。
ブロック付きメソッドの作り方を説明します。
モジュールには名前空間とミックスイン(Mix-in)の2つの機能があります。 ここではミックスインについて説明します。
クラスの親子関係
Rubyの演算子とその再定義について書きます。
今回からクラスとインスタンスを定義、生成する方法を説明します
Kernelモジュールのメソッドはどこでも使うことができます。 そのメソッドの中には便利で有用なものが多いです。
ここでは私が便利だと思ったメソッドを紹介します。
実数
今回はシンボルとハッシュについて説明します。
文字列は最も使うオブジェクトのひとつです。 特にウェブ・アプリケーションでは、コンテンツだけでなくHTMLのタグやCSSを含めすべてが文字列です。 Rubyは文字列オブジェクトのメソッドが充実しており、またパターンマッチのための正規表現も充実しています。
配列は、どのプログラミング言語にもあると思います。 複数の要素を一括して扱うことができるのが配列です。 Rubyの配列はメソッドが充実しているので、プログラムを効率的、機能的に書くのに役立ちます。
今回の目標はインスタンスです。 インスタンスを説明するために、ローカル変数と文字列オブジェクトを事前に扱います。
今回はメソッド定義です。 メソッド定義はRubyの核心ですが、今回はトップレベルに限って説明します。 この限定によって、内容はかなり易しくなっています。
ブロックはRubyの特長です。 ブロックのおかげで記述が非常にすっきりと分かりやすくなります。 今回はブロックをイテレータの本体として使う方法を説明します。
ここではRubyの最も基本的なオブジェクトである整数について説明します。
「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。