単項マイナスと構文解析
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合
ここでは私が便利だと思ったメソッドを紹介します。
mapは配列で最も使うメソッドのひとつです。 各々の要素に対してブロックを実行し、その値からなる新しい配列を返します。
print [1,2,3].map {|i| i+1} #=>[2, 3, 4]
#から改行まではRubyのコメントです。
コメントは実行の対象ではなく、プログラマーが説明やメモを書くためのものです。
Rubyの習慣として#=>
は実行したときの画面出力を書いたり、式の値を書いたりします。
上のプログラムのコメントの意味は「プログラムを実行すると[2, 3, 4]が画面に現れる」ということです。
今までプログラムと実行結果を別々に書いていたのですが、この書き方でよりコンパクトに書くことができます。
ひとことでこのプログラムを表現すると「配列の各要素に1を加えた配列を求める」ということになります。 mapは配列オブジェクトを新たに作るので、元のオブジェクトは変更されません。
ディレクトリdir1/dir2
以下のすべてのファイルのパス名の配列を作り、表示するには
d = "dir1/dir2"
paths = Dir.children(d).map {|file| d + "/" + file}
paths.each {|p| print "#{p}\n"}
mapメソッドもeachメソッドもブロックが短いので波カッコを使うのが良いと思います。 そうすることでプログラム全体の行数を抑えることができ、プログラムの全体を見渡すことができるようになります。
私は以前はdo〜endをブロックに用いることが多かったのですが、最近は波括弧が多くなってきました。 その使い分けはブロックが長いか短いかで決めています。
mapでできることはeachでもできます。 最初の1を足す例をeachで書き直すと
b = []
[1,2,3].each {|i| b << i+1 }
print b, "\n" #=> [2, 3, 4]
eachを使う場合は空の配列bを用意して、そこに1を加えた要素を追加していくことになります。 mapより複雑なことをしていることがわかると思います。
一般に、配列は関連した要素(例えばあるディレクトリ直下のファイル全体)の集合を表します。 そのような集合の要素に対しては「共通の操作」を行うことが多いです。 mapはそのような共通の操作をまとめて行います。 ひとつひとつの要素に操作をするeachと比べ、まとめて行えるmapの方が優れているといえます。
injectは「たたみこみ演算」を行います。 要素をひとつずつ取り出し、操作を行い、その結果を次の要素との演算に使います。 例えば配列[1,3,5]の要素を合計する操作を考えましょう。
この操作は同じ演算を繰り返し行っています。 これが「たたみこみ演算」です。
print [1,3,5].inject {|i, j| i+j}, "\n" #=> 9
計算の初期値として引数を与えることもできます。 例えば、mapで[1,2,3]から[2,3,4]を作ったのと同じことをinjectで実現することができます。
print [1,2,3].inject([]) {|i, j| i << j+1}, "\n" #=>[2,3,4]
[ ]
がiに代入されるこれは、eachメソッドを使ったのと同じ方法です。 injectはeachに比べ、1行でコンパクトに書けるのが長所です。 私は以前はeachを使っていたのが、最近はinjectを使うようになりました。
sortは配列をソートする(整列する)メソッドです。 たとえば
[1,3,2].sort
=>[1,2,3]を返す(この配列は新規に作られたもので元の[1,3,2]はそのまま)ソートをするためには、配列要素に<=>
メソッドが定義されていることが必要です。
このメソッドはa <=> b
に対し
を返します。
整数や文字列には<=>
演算子があらかじめ定義されています。
なお、この演算子は「宇宙船演算子」といわれます。
その形がUFOに似ているからだといわれますが、その由来には諸説あるようです。
この演算子は様々なプログラム言語に実装されていて、比較(<
、=
、>
)の元になる役割を果たしています。
sortは宇宙船演算子が定義されていないオブジェクトに対しては、ブロックで大小を評価することによってソートすることができます。 また、宇宙船演算子があっても、別の基準でソートしたいときはブロックを用います。 例えば、[1,3,2]を大きい順にソートするには、宇宙船演算子の符号を逆にするためにマイナスをかけます。 以下では小さい順と大きい順の両方を示します。
print [1,3,2].sort, "\n" #=>[1,2,3]
print [1,3,2].sort{|a,b| -(a<=>b)}, "\n" #=>[3,2,1]
数の文字列”9”、”5”、”13”、”20”、”12”、”4”を文字列としてソートするのと、数字としてソートするのでは結果が違います。
a = ["9", "5", "13", "20", "12", "4"]
print a.sort, "\n"
print a.sort{|a,b| a.to_i<=>b.to_i}, "\n"
to_iは文字列を整数に変換するメソッドです。 実行すると
["12", "13", "20", "4", "5", "9"]
["4", "5", "9", "12", "13", "20"]
となります。 文字列のソートは辞書順なので”12”が”4”よりも前にきます。
uniqは重複を除くメソッドです。
[1,2,2,2,3].uniq #=>[1,2,3]
これは文字列の配列を扱っている時に使うことが多いです。
include?はあるオブジェクトが配列の要素になっているときにtrue、そうでないときにfalseを返します。
[1,3,5,7].include?(7) #=> true
[1,3,5,7].include?(8) #=> false
each系のメソッドは大変良く使います。 eachはすでに解説したので、このセクションでは省略します。
to_sメソッドはすべてのオブジェクトで実装されています。 そのオブジェクトを文字列に直すメソッドです。
1.to_s #=> "1"
1.23.to_s #=> "1.23"
[1,2].to_s #=> "[1, 2]"
1..2.to_s #=> "1..2"
{one: 1, two: 2}.to_s #=> {:one=>1, :two=>2}
このメソッドはprintメソッドの中で使われています。 printメソッドは、引数が文字列でなければto_sメソッドを使って文字列に直して表示します。 そのおかげで、任意のオブジェクトをprintが出力できるわけです。
ここでちょっとした注意。
print {one: 1, two: 2}
とするとエラーになります。 これはこのプログラムに曖昧さがあるためです。 メソッドの次には引数だけでなくブロック(実はブロックも引数なのですが)が来る可能性があります。 波括弧がブロックを表すとすると、ブロックの中が「one: 1, two: 2」で、これを無理やり実行しようとするとコロンのところでエラーになってしまいます。 このような曖昧さを避けるには丸括弧を使ってください。
print ({one: 1, two: 2})
printと丸括弧の間にスペースが無いほうが普通なのですが、あったとしてもこの文は実行できます。
to_sメソッドはダブルクォート文字列の式展開でも使われます。
式展開では、その式が文字列でなければto_sを使って文字列に直してから埋め込みます。
"abc = #{100}"
では、100は整数なのでto_sが使われます。
このようにto_sは様々な場面で背後で活躍しているわけです。
to_sを直接使うことは少ないと思いますが、to_sのおかげでプログラム中の表現が簡潔になっていることが多いです。
<<メソッドは文字列、配列、整数などで使われますが、オブジェクトによって意味が違うメソッドです。 また、このメソッドは二項演算子として使えますが、糖衣構文によってメソッドであると解釈されて実行されます。
"abc" << "de" #=> "abc".<<("de") => "abcde"
>>
があり、これは右にビットをずらす。
このとき小数点以下は切り捨てられる余談ですが、機械語に近いレベルでは左シフトが2倍、右シフトが1/2倍を高速で行える演算としてよく用いられます。
文字列のメソッドです。
配列や文字列で使うメソッドで要素数、文字数を返します。
現在の時刻のTimeオブジェクトを返します。
print Time.now, "\n" #=> 2022-09-19 16:10:15 +0900
年月日、時分秒が表示されます。 最後の「+900」はAsia/Tokyoの協定標準時(UTC)からの時差です。 したがって、UTCは「2022-09-19 7:10:15」になります。 UTCとの差が無いのはヨーロッパやアフリカのいくつかの国です。 アイスランドのレイキャビクの標準時はUTCに一致します。
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合の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の最も基本的なオブジェクトである整数について説明します。
「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。