単項マイナスと構文解析
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合
Rubyのクラスには親子関係があります。 あるクラスの子をサブクラスといいます。 サブクラスは複数作ることができますが、親クラス(スーパークラス)を子から作ることはできません。 したがって、この親子関係はツリー状になります。
すべてのクラスの祖先はBasicObjectというクラスです。
あるクラスがどういう祖先を持っているかはancestors
メソッドで分かります。
p String.ancestors
これを実行すると
[String, Comparable, Object, Kernel, BasicObject]
と表示されます。 左から右へ「子から親」の順に並んでいます。 このうちComparableとKernelはクラスではなくモジュールです。 モジュールについては別の記事で説明します。 クラスだけの親子で言えば
String => Object => BasicObject
ということになります。 以下では子クラスを「サブクラス」、親クラスを「スーパークラス」と呼びます。
サブクラスはスーパークラスの性質、例えばメソッド、インスタンス変数を受け継ぎます。
親から子になるにつれ、より個別的、具体的なクラスになっていきます。
サブクラスの定義は<
をクラス名の後につけ、さらにスーパークラスを置きます。
class A < B
end
この例ではAがBのサブクラス、BがAのスーパークラスです。 BはRubyが既に定義しているクラスでも、ユーザが新たに定義したクラスでも構いません。
ここではサブクラスの例として統計のサンプルデータの集合を表すクラスを作ってみましょう。
今回は都道府県別人口のデータを処理するクラスを作ってみます。 データは独立行政法人統計センターのSSDSE(教育用標準データセット)から取ってきました。
https://www.nstac.go.jp/use/literacy/ssdse/
2022/9/22の時点では「SSDSE-E-2022v2」(2022年第2版)が最新です。
データの中から都道府県名と人口をセットにして、ヒア・ドキュメントの文字列にしました。
北海道 5224614
青森県 1237984
... ...
都道府県と人口の間はタブで区切られています。 このデータをハッシュにして取り出すには
それぞれの項目はメソッドで実現できます。 全体として連続したメソッドになりますが、これを「メソッド・チェーン」ということもあります。 ここまでをプログラムにしましょう。 少し長くなりますが、全都道府県の人口データもプログラムリストに入れておきます。
d = <<EOS
北海道 5224614
青森県 1237984
岩手県 1210534
宮城県 2301996
秋田県 959502
山形県 1068027
福島県 1833152
茨城県 2867009
栃木県 1933146
群馬県 1939110
埼玉県 7344765
千葉県 6284480
東京都 14047594
神奈川県 9237337
新潟県 2201272
富山県 1034814
石川県 1132526
福井県 766863
山梨県 809974
長野県 2048011
岐阜県 1978742
静岡県 3633202
愛知県 7542415
三重県 1770254
滋賀県 1413610
京都府 2578087
大阪府 8837685
兵庫県 5465002
奈良県 1324473
和歌山県 922584
鳥取県 553407
島根県 671126
岡山県 1888432
広島県 2799702
山口県 1342059
徳島県 719559
香川県 950244
愛媛県 1334841
高知県 691527
福岡県 5135214
佐賀県 811442
長崎県 1312317
熊本県 1738301
大分県 1123852
宮崎県 1069576
鹿児島県 1588256
沖縄県 1467480
EOS
d = d.split(/\n/)\
.map{|s| s.split(/\t/)}\
.map{|a| [a[0].to_sym, a[1].to_i]}\
.to_h
最後から2〜4行目の最後にバックスラッシュがあります。 これは改行を取り消すためのもので、次の行も同じ一行にくっつけるという意味です。 Rubyでは改行が空白よりも強い区切り(文の区切り)であるので、これをつけておきます。 ただし、これは一般論であり、上記のようなメソッドチェーンではバックスラッシュを取り去ってもRubyは同じように解釈してくれます。 好みの問題ですが、バックスラッシュをつけるほうが文のつながりを意識できて良いと思います。 to_hメソッドは配列をハッシュに変換します。 変換するには配列の内容がハッシュに対応するものでなければなりません。 詳細はRubyのドキュメントのArrayを参照してください。
結果としてdは
d = {:北海道=>5224614, :青森県=>1237984, ... ... ... , :沖縄県=>1467480}
となります。
ハッシュのサブクラスStatを統計処理のために作ります。 Statの中身はハッシュと同じですが、次のようなメソッドを作ります。
最初の3つは検索結果をStatオブジェクトで返します。 平均値は小数点以下第1位までに丸めた実数を返します。 最後の2つは並び替えられたStatオブジェクトを返します。
これらの機能はハッシュにはないものです。
class Stat < Hash
def initialize h={}
super()
update(h)
end
def find_by_value(v)
Stat.new(select{|key, value| value == v})
end
def max
m = map{|k,v| v}.max
find_by_value(m)
end
def min
m = map{|k,v| v}.min
find_by_value(m)
end
def average
(map{|k,v| v}.sum.to_f/size).round(1)
end
def sort
Stat.new(super{|a,b| a[1]<=>b[1]}.to_h)
end
def reverse
Stat.new(to_a.reverse.to_h)
end
end
このプログラムで注意真ければならないのはself
という特別な変数(疑似変数)です。
selfは「その」オブジェクト自身を表します。
def abc
self.clear
clear
end
メソッドabcの定義の中のselfとは、次のようなオブジェクトです。
例えばそのオブジェクトが変数xx
に代入されていて、xx.abc
が実行されたとき、self
は変数xx
の指すオブジェクトになります。
同じクラスの別のオブジェクトが変数yy
に代入されていて、yy.abc
が実行されたときはself
はyy
の指すオブジェクトになります。
ですので、selfは固定されたオブジェクトではなく、メソッドabc
が呼ばれたときのabc
が属するオブジェクトになります。
このように、メソッドにはかならずそのメソッドとセットになったオブジェクトがあり、そのオブジェクトをメソッドのレシーバーとも言います。
ですから、「selfはメソッドabcのレシーバーを表す」とも言えます。
1行目はselfを空のハッシュにします。 2行目はレシーバーが書かれていません。 メソッド名だけです。 「メソッド名だけでメソッドが呼ばれたときのレシーバーは、selfとする」という約束があります。 ですから2行目と1行目は同じ結果をもたらします。
それでは、Statクラスの定義を説明しましょう。 クラス定義の中にはレシーバが省略されたメソッドが多数出てきますので注意してください。
class Stat < Hash
の部分がそれを表す)Stat.new
が呼ばれたとき、initializeメソッドが初期化をする。
h={}
というパラメータがあるので、newメソッドには引数をつけることができる。
引数が与えられなかったときのデフォルト値は{}
、つまり空のハッシュ。
super()
はこのメソッドのスーパークラスにおける同名のメソッドを呼び出す。
つまりHashのinitializeメソッドが呼び出される。
したがって、super()は空のハッシュ・インスタンスを生成、初期化する。
updateはレシーバが省略されたメソッドなので、selfをレシーバとして実行される。
updateはHashのメソッドで、引数を破壊的に付け加える。
以上から、Stat.newにハッシュが引数で与えられたときは、そのハッシュを中身とするStatオブジェクトが生成される。
引数がなければ空のStatオブジェクトが生成される説明は長くなってしまいましたが、これはメソッドチェーンでたくさんのことをコンパクトにプログラムしたからです。 逆にいえば、「Rubyでは短いプログラムで多くのことを実行できる」ということになります。
データの定義、Statクラスの定義に続けて、次のプログラムを書き加えます。
s = Stat.new(d)
p s.find_by_value(7344765)
p s.find_by_value(0)
p s.max
p s.min
p s.average
p s.sort
p s.sort.reverse
実行してみましょう。
{:埼玉県=>7344765}
{}
{:東京都=>14047594}
{:鳥取県=>553407}
2683959.6
{:鳥取県=>553407, :島根県=>671126, ... ... ... , :東京都=>14047594}
{:東京都=>14047594, :神奈川県=>9237337, ... ... ... , :鳥取県=>553407}
d
を用いてStatオブジェクトs
を生成クラスを作ったことにより、これらの統計処理がメソッドひとつで実行できるようになりました。 このクラスは都道府県人口以外の統計処理にも使えます。
また、標準偏差やヒストグラム(グラフィックの手段が必要)などもメソッドで用意すればもっと実用的になるでしょう。
今回はサブクラスを取り上げました。 StatクラスはHashのすべてのメソッドを使うことができるので、一から作るよりも少ない労力で作成することができました。 このようにサブクラスの仕組み(これを継承ともいう)はプログラムの資産を活かすことにつながるわけです。
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合の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の最も基本的なオブジェクトである整数について説明します。
「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。