LoginSignup
3
0

More than 1 year has passed since last update.

チャート式ruby-II(variable and method)

Last updated at Posted at 2020-10-28

!Mac OS X-10.15.7 !ruby-2.7.1p83

variable

チャート式Rubyの2回目,変数とメソッドです.

お題

受け取った引数ARGV[0]をnameという変数(variable)に代入してそれを打ち出すcodeを書け.

> ruby name_variable.rb Rudy
Rudy

簡単な解説

rubyの変数は型宣言の必要性がありません.文脈に合わせて適当に型が定められます.イコールで代入されます.

name = 'Rudy'

なんかです.

詳しい解法

> ruby name_variable.rb Rudy

としましょう.

ruby: No such file or directory -- name_variable.rb (LoadError)

というエラーが返ってきますよね.そんなファイルないよって.なら作ります.

> emacs name_variable.rb

としてemacsを起動して

p "Rudy"

と打ち込んでsaveしましょう.

> ruby name_variable.rb Rudy
"Rudy"

 

類題

さてこの後,

  • nameに代入してRudyと打ち出すようにrefactoringしてください.
  • ARGV[0]を受け取って,自分の名前を返すようにrefactoringしてください

p "Rudy"

method

お題

> ruby hello_method.rb Rudy
Hell Rudy.

と返すhello methodを作りなさい.

解説

Rubyではfunctionやprocedureなどのまとまりはmethodを定義(definition)することになります.methodは0個以上の引数(argument)を取ることができます.例えば次の通りです.

def hello(name)
  p name
end

解法

> ruby hello_method.rb Rudy

として見ましょう.もちろん動きませんよね.emacsでhello_method.rbを編集します.

> emacs hello_method.rb

何ですが,methodの中身ではなく呼び出す方から考えます.普通に,

hello(name)

と打ち込んで動かして見てください.

> ruby hello_method.rb Rudy
hello_method.rb:1:in `<main>': undefined local variable or method `name' for main:Object (NameError)

というエラーが返ってきたはずです.nameという変数やmethodがundefineやと怒られています.そこで今まで学んできたのを思い出して,nameにARGV[0]を代入します.

name = ARGV[0]
hello(name)

次のerrorは

> ruby hello_method.rb Rudy
hello_method.rb:2:in `<main>': undefined method `hello' for main:Object (NoMethodError)

でhelloっていうmethodがないよですね.

類題

先の解法を参照してhello メソッドを完成させてください.

def hello(name)
  puts "Hello #{name}."
end
name = ARGV[0]
hello(name)

ここで学んだこと

  • ruby
    • variable
    • method
    • argument

TDD

codingの最終目標

こういうcodingの仕方はTDD(Test Driven Development:テスト駆動開発)と呼ばれています.

  • テストを作る
  • エラーを出す(red)
  • エラーをなくす(green)
  • codeを綺麗にする(refactoring)

です.codingの最終目標は

clean code that works

動く綺麗なコードを作ることです.順番は,まず動かして,それからこそこそと綺麗にするです.えっと,もし,あなたが,

  • codeを書くまえに設計すべき
  • コピペは悪

なんていう,マントラを信じているならこのprogramming styleを提唱し始めたKent Beckの文章を載せておきます.よーーく心に刻んでください.

もしあなたがプログラミング嫌いならば,少し心が晴れると思いますよ.俺のせいじゃないって.

clean code that works

TDD by Example (Kent Beck) p.13

目指すのは,動作するきれいなコードだ(このRon Jeffriesの簡潔な表現は素晴らしい).動作するきれいなコードは,偉大なプログラマでもすぐには書けないことがあるし,普通のプログラマならなおさらだ(私もそうだ).=ここは分割統治しよう.=各個撃破だぜ,ベイビー.最初に「動作する」に取り組み,その後で「きれいな」に取り組む.この方法はアーキテクチャ駆動とは正反対だ.アーキテクチャ駆動は「きれいなコード」に最初に取り組み,そのうえで苦心してあちこち設計の辻褄を合わせながらどうにか「動作する」を実現させる.

TDD by Example (Kent Beck) p.11

The goal is clean code that works(thenks to Ron Jeffries for this pithy summary).Clean code that works is out of the reach of even the best programmerssome of the time,and out of the reach of most programmers(like me)most of the time.Divide and conquer, baby.First we'll solve the "that works" part of the problem.Then we'll solve the "clean code" part.This is the opposite of architecture-driven development,where you solve "clean code" first,then scramble around trying to integrate into the design the things you learn as you solve the "that works" problem.

phases and speed

TDD by Example (Kent Beck) p.30

グリーンバーを出す小さなステップはどんなものだろうか.Dollarクラスを丸ごとコピーして,DollarをFrancに書き換えるのはどうだろう.

ちょっと待った.これで唾棄すべき糞コードの出来上がりだとあざ笑う声が聞こえる.その声は続けて言う.コピー&ペーストによる再利用は抽象化の敗北であり,きれいな設計を殺すと.

イラっとしただろうか.なら深呼吸だ.鼻から息を吸い込んで,3秒止めて口から吐き出す.オーケー?さて,サイクルにはフェーズがあることを思い出してほしい(中には数秒で通り過ぎるものもあるが,フェーズはフェーズだ).

  1. テストを書く.
  2. コンパイラを通す.
  3. テストを走らせ,失敗を確認する.
  4. テストを通す.
  5. 重複を排除する.

各フェーズにはフェーズなりの目的と解決法があり,価値観も異なっている.最初の3つのフェーズはなるべく速く通過して,新しい機能がどの状態にあるのかわかるところまで行きたい.そこにたどり着くためには,どのような罪をおかしてもよい.その短い時間だけは,速度が設計よりも重要だからだ.

1つ心配なのは,私がここに書いていることが,良い設計の原則を無視してよいという免罪符になってしまうことだ.チームに対して「Kent Beckが設計なんてどうでもいいって書いてたよ」などと言い始めるのは,ちょっと待ってほしい.サイクルはまだ終わっていない.4つ足のアーロンチェアは倒れる.最初の4つのステップは,5つ目がなければ無意味だ.正しい設計を,正しいタイミングで行う.動かしてから,正しくする.

ここまで言っておけば安心だろう.これで読者の皆さんは重複を排除するまで誰にもコードを見せないはずだ(ただし,ペアプロ相手は除く)

TDD by Example (Kent Beck) p.23

What short step will get us to a green bar?Copying the Dollar code and replacing Dollar with Franc.

Stop. Hold on.I can hear the aesthetically inclined among you sneering and spitting.Copy-and-paste reuse?The death of abstraction?The killer of clean design?

If you're upset, take a cleanthing breath.In through the nose … hold it 1, 2, 3… out through the mouth.There. Remember, our cycle has different phases(they go by quickly, often in seconds, but they are phases.):

  1. Write a test.
    1. Make it compile.
    2. Run it to see that it fails.
  2. Make it run.
  3. Remove duplication.(Make it right.)

The different phases have different purposes.They call for different styles of solution, different aesthetic viewpoints.The first three phases need to go by quickly,so we get to a known state with the new functionality.We can commit any number of sins to get there,because speed trumps design,just for that brief moment.

Now I'm worried.I've given you a license to abandon all the principles of good design.Off you go to your teams –"Kent says all that design stuff doesn't matter."Halt. The cycle is not complete.A four-legged Aeron chair falls over.The first four steps of the cycle won't work without the fifth.Good design at good times.Make it run, make it right.

There, I feel better.Now I'm sure you won't show anyone except your partner your codeuntil you've removed the duplication.Where were we?Ah, yes.Violating all the tenets of good design in the interest of speed(penance for our sin will occupy the next several chapters).

おまけ

言語は英語から

これをmethodにしたら,

def func(hoge)
  puts "Hello #{hoge}."
end

hoho = ARGV[0]
func(hoho)

これを動かしてみましょう.

> ruby hello.rb bob

とちゃんと動きます.これでは何をしているのかわからないので,コメントをつけましょう.

# method: func
# input:  hoge is a name
# output: puts greetings
# return: nil
def func(hoge)
  puts "Hello #{hoge}."
end

honya = ARGV[0] # get hoho from argv
func(honya) # call hello with a name honya

英語でしっかりとコメントが書ければ世界中に通用するcodeが書ける…んでしょうかね?コメントをぐちゃぐちゃ書くんじゃなくて,もっとわかりやすい名前(method名,変数名)にしたくなるでしょう?

def puts_hello name
  puts "Hello #{name}."
end

name = ARGV[0]
puts_hello name

こっちの方が短くてスッキリしていて圧倒的にいいでしょ? 適切な英単語を使えば,要らん説明が省けます.これが言語は英語からという意味です.

長くなったら,隠せ

もしoptionのnameを打つのを忘れたら,問い合わせてくれると,user interfaceという感じがもっとするでしょう?

name = ARGV[0]
if name == nil
  puts "What\'s your name?"
  name = gets.chomp
end

というのをname=の下につけましょう[1].ちょっと動かして見ましょう.

> ruby hello.rb

意図通りに動いていますか? でもmain loopが長くなってきちゃいました.そこで,これもmethodに切り出します.領域を指定して(C-spaceで先頭を指定して移動),C-wでcut, 移動してC-yでyankです.

def gets_name
  name = ARGV[0]
  if name == nil
    puts "What\'s your name?"
    name = gets.chomp
  end
  return name
end

name = gets_name

この時,領域を指定してM-x indent-regionとしてください.あるいはC-x TAB.これだけでもだいぶ読みやすくなったでしょ?

もっとできます.main loopにcursorを持って行って,'C-c @ C-l'と打ってみてください.

def puts_hello name...end

def gets_name...end

name = gets_name
puts_hello name

これがoutlineによるtoggle表示からきたすごいメタファなんですよ.何をしているのか知らなくていい部分は隠してしまおうというのが,methodに切り分ける理由なんです.

今日の教え- editor -

ここで示した優秀なeditorのmeritは納得いただけましたでしょうか?必須操作を少しだけリストアップしておくと,

  1. editのkey-bind
  2. syntax high_lighting
  3. code hiding, show
  4. block copy, 移動
  5. query-replace
  6. shellとの連携

  • source ~/git_hub/ruby_docs/chart_style_ruby/c2_method_hello.org
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0