第 28 回 Ruby/Rails 勉強会

いつものように勉強会に参加してきました。

今回は発表の数を減らして、ゆとりを持って「ゆるふわ」感でやってみたつもり。
でも、発表が少ないのは不評だったみたいだ。

エラトステネスの嵐 by 小波せんせい

大学教授の講義が聞ける、たいへん貴重なセッション。

大昔 (20 数年前) 何かの雑誌で「エラトステネスとライフゲーム作ったことないやつはモグリだ」とか書いてあるのを見た気がする。
未だに、どっちも真面目にやったことないけど。

教訓
プロファイルとベンチマークを同時に撮っても意味はない。

確かに。

今まで、プロファイル用とベンチマーク用のラッパを別々に作ってたけど、ひとつのラッパでいけそうだ。

defined? Profiler__    # => nil
require 'profile'
defined? Profiler__    # => "constant"

git - 分散バージョン管理システム by 舘野祐一さん

今回のスペシャルゲスト舘野さん。

なんで最近こんなに git が熱いのか謎だった。

github が大人気だけど、Web UI が同じなら、べつに svnhub とか作れば、それで良くね? とか思ってた。

でも、それは間違いだった。

git いい。

気軽に使えて、動作も速い。

clone したものを push するだけじゃなく、pull で反映させられるって言うのもいい。

Ruby 初級者向けレッスン 第 22 回 by okkez さん & もりさん

Rubyist の基本 irb について。

演習問題の「動作中、一時的に結果表示を消してみよう」が難しすぎ。
irb の勉強というより、マニュアルの捜し方の勉強?
IRB.conf で設定変更するのかと思いきや、IrbCommands#conf を使わないと動的に変更できないらしい。

irb にて、

methods.grep /conf/       # => ["conf"]
conf.class                # => IRB::Context
conf.methods.grep /echo/  # => ["echo", "echo=", "echo?"]
conf.echo                 # => true
conf.echo = false         # => (なにも返さない)
conf.echo = true          # => true (もとに戻す)
self.class.ancestors      # => [Object, Math, Kernel] (えー! IrbCommands は?)

irb.rb 嫁ってことか?

演習問題「計算 100 もどきを作りましょう」

計算 100 って NINTEND○ DS の脳トレのやつ?

class Question
  def initialize(level = :easy)
    @question = (level==:easy)? easy_question: hard_question
    a, op, b  = @question
    @answer   = a.__send__(op, b)
  end

  def q; "%2d %s %2d = " % @question; end
  def a(answer) answer == @answer; end

  private

  def easy_question; question(10, [:+, :-, :*]); end
  def hard_question; question(100, [:+, :-, :*, :/]); end

  def question(max, operator)
    op = operator.choice
    case op
    when :-
      substruct_question(max)
    when :/
      divide_question(max)
    else
      [rand(max), op, rand(max)]
    end
  end

  def substruct_question(max)
    a = rand max
    b = rand max
    a, b = b, a  if a < b
    [a, :-, b]
  end

  def divide_question(max)
    a = rand(max-1) + 1
    b = (2..(Math.sqrt(a).to_i)).inject([]) do |divided, b|
      divided.tap do
        if a % b == 0
          divided << b
          divided << a/b
        end
      end
    end.choice
    b = [1, a].choice  unless b
    [a, :/, b]
  end
end


if $0 == __FILE__
  require 'optparse'
  level = :easy
  opt = OptionParser.new
  opt.banner = <<USAGE
usage #{File.basename($0)} [options] [number of questions]
options:
USAGE
  opt.on('-e', 'easy'){level = :easy}
  opt.on('-d', 'difficult'){level = :hard}
  opt.parse!(ARGV)

  n = ARGV.shift.to_i
  n = 20  if n == 0

  questions = n.times.map{Question.new(level)}

  ng = 0
  st = Time.now

  questions.each_with_index do |question, i|
    print "%d 問 突破\n\n" % i  if i%10 == 0 && i != 0

    print question.q
    if question.a($stdin.gets.to_i)
      puts ""
    else
      puts "		×"
      ng += 1
    end
  end

  time = Time.now - st

  puts "正解:	%4d 問" % (questions.size - ng)
  puts "不正解:	%4d 問" % ng
  puts "タイム:	%4d 分 %d 秒" % time.divmod(60)
end
  • デフォルトで計算 20 の「かんたん」になるようにしてみた。
  • 引き算の答えが負数にならないようにした。
  • 割り算の問題が 0 / n はめんどいので諦めた。
  • 割り算のテスト中、n / m の n が素数ばっかり出たときはウケた。
    • 割り切れる問題が作れんがな。