第28回 Ruby/Rails勉強会@関西に参加
日本Rubyの会 公式Wiki - 第28回 Ruby/Rails勉強会@関西
http://jp.rubyist.net/?KansaiWorkshop28
自転車で京女の前の坂を汗だくになって登った上、ぎりぎりの到着でばたばたしてしまい、エラトステネスの嵐はちゃんと聴けなかった。
id:secondlifeさんのGitの解説は、これは使ってみたくなるなあ、という強力なもので、この日一気に信者を増やしたんじゃないだろうか。
branch切り替えとか異様に高速だったんですが、ファイルが大量にあってもやはり切り替え速いんだろうか。Subversionの場合、特にeclipseでSubclipse使って作業したりすると逐一時間がかかって苛々しまくるのだが。それからTrac+Subversionの連携は便利だけど、Trac+Gitも良い感じに組み合わせられるのかな?とか、windowsで問題なく使えるようにGUIクライアントとかeclipseプラグインとか出ないと辛いな、とか、良く考えるとGitをメインに使うには色々なハードルが。
ちなみにGitは「ギット」なのか「ジット」なのかどっちなんだ?と思っていたんだけど、皆さん普通にギットと発音していたのでそうなのか?なんとなくジットかと思っていたのだけど。
初心者レッスンはirbの説明。irbをカスタマイズして使おうとか考えたことがなかったので、なるほどという感じで楽しめた。okkezさんのブログのエントリに設定ファイルが載っているので、とりあえずこれをそのまま頂いて使おう。
演習では、irbの結果表示を消す方法が分からずに苦労してしまった。一応conf.return_format = ""で消えたけど、こんなんでいいのか。あとはirb_context.echo = falseとか。
以下は計算100もどきの回答。なんかこの前の石取りゲームと似た感じになってしまうので、ステートはlambda使ってみたりした。rubyだったら、State/Strategyといったパターンは、クラス使う替わりにlambdaでやるのも良いかも。コード長いけど、表示とロジックは分離してないと気持ち悪くて仕方ないので、個人的にはこれで良し。include Observableするだけで一発でObserverが書けるrubyは最高。
require "observer" QUESTION_NUMBER = 100 class UI def initialize(hundred_calc) @hundred_calc = hundred_calc @hundred_calc.add_observer(self) @response = Response.new(@hundred_calc) @hundred_calc.update(nil) end def update print @response.render exit if @hundred_calc.state.nil? @hundred_calc.update(gets.strip) end end class Response def initialize(hundred_calc) @calc = hundred_calc end def render send(@calc.result.to_s) end def greeting "計算 100 開始\n" + select_level end def select_level "難易度を選択してください。1:かんたん 2:むずかしい >" end def level (@calc.level == 1 ? "かんたん" : "むずかしい") + " を開始します。Press Enter >" end def first_question question end def correct_continue correct + question end def error_continue error + question end def correct_check_point correct + check_point + question end def error_check_point error + check_point + question end def correct_finish correct + summary end def error_finish error + summary end def correct "正解\n" end def error "不正解 (正解: #{@calc.answer(@calc.question_count - 1)})\n" end def question "#{@calc.question(@calc.question_count)} = " end def check_point "#{@calc.question_count} 問突破\n" end def summary m, s = (@calc.end_time.to_i - @calc.start_time.to_i).divmod(60) check_point + "#{QUESTION_NUMBER} 問終了しました\n" + "正解 : #{@calc.correct_count} 問\n" + "不正解 : #{@calc.error_count} 問\n" + "タイム : #{m} 分 #{s} 秒\n" end end class HundredCalc include Observable LEVELS = {1 => :easy, 2 => :difficult} attr_accessor :state, :input, :result, :level, :correct_count, :error_count, :question_count, :start_time, :end_time, :questions def initialize @level = nil @correct_count = 0 @error_count = 0 @question_count = 0 @start_time = nil @end_time = nil @questions = [] initialize_states @state = @initial_state end def update(input) @input = input @state.call changed notify_observers end def correct?(question_count, answer) @questions[question_count].correct?(answer) end def question(question_count) @questions[question_count].expression end def answer(question_count) @questions[question_count].answer end private def create_question(question_count) @questions[question_count] = Question.new end def initialize_states @initial_state = lambda do @result = :greeting @state = @select_level_state end @select_level_state = lambda do if LEVELS.include?(@input.to_i) @level = @input.to_i Question.send(LEVELS[@level].to_s) @result = :level @state = @start_state else @result = :select_level @state = @select_level_state end end @start_state = lambda do (0...QUESTION_NUMBER).each {|i| create_question(i) } @question_count = 0 @start_time = Time.now @result = :first_question @state = @question_state end @question_state = lambda do correct = @input =~ /\A-?\d+$/ && correct?(@question_count, @input.to_i) if correct @correct_count += 1 else @error_count += 1 end @question_count += 1 if QUESTION_NUMBER <= @question_count @end_time = Time.now @result = correct ? :correct_finish : :error_finish @state = nil else if @question_count % 10 == 0 @result = correct ? :correct_check_point : :error_check_point else @result = correct ? :correct_continue : :error_continue end @state = @question_state end end end end class Question @@expression_builder = nil def self.easy @@expression_builder = lambda do op = %w[+ - *][rand(3)] left = rand(10) right = op == "/" ? rand(9) + 1 : rand(10) "#{left} #{op} #{right}" end end def self.difficult @@expression_builder = lambda do op = %w[+ - * /][rand(4)] if op == "/" #除数が大きいとつまらないので right = rand < 0.9 ? rand(20) + 1 : rand(99) + 1 left = right * (rand(100 / right) + 1) else right = rand(100) left = rand(100) end "#{left} #{op} #{right}" end end attr_reader :expression, :answer def initialize @expression = @@expression_builder.call @answer = eval(@expression) end def correct?(answer) @answer == answer end end if $0 == __FILE__ UI.new(HundredCalc.new) end