gotagota日記

「面白きことは良きことなり」

『たのしいRuby 第4版』 第14章 文字列(String)クラス

第14章 文字列(String)クラス

模範解答はこちら

(1)

問題

"Ruby is an object oriented programming language" という文字列に含まれる各単語を要素とする配列を作れ、という問題です。

私的解答
str = "Ruby is an object oriented programming language"
ary = str.split(/ /)
p ary

split メソッドを使って単純に分割で大丈夫そうです。
引数に何も指定しなければ空白文字による分割になるので、それでもよかった。

(2)

問題

(1)の配列をアルファベット順に並べ替えろ、という問題です。

私的解答

str = "Ruby is an object oriented programming language"
ary = str.split(/ /)
p ary.sort

sort メソッドを使えば一発です。

(3)

問題

(2)の配列を大文字、小文字の区別なしにアルファベット順に並べ替えろ、という問題です。

私的解答
str = "Ruby is an object oriented programming language"
ary = str.downcase.split(/ /)
p ary.sort

模範解答のように sort_by メソッドでブロックを作ってそっから配列にするのもいけめんだと思います。

(4)

問題

(1)の文字列に含まれる全ての単語の先頭を大文字に変換しろ、という問題です。

私的解答
str = "Ruby is an object oriented programming language"
newStr = ""
str.gsub(/\s/, "\n").each_line do |line|
  newStr << line.capitalize
end
p newStr.gsub(/\n/, "\s")

今見返すと、二度手間な変換をおこなっていてあまり美しくありませんね。。。
模範解答にあるように、collect(もしくは map) メソッドを使って方が可読性の面でもいいですねー。

(5)

問題

(1)の文字列に含まれる文字とその数を次のような形式で表示させろ、という問題です。

' ': *******
'R': *
'a': ****
'b': **
'c': *
:
:
私的解答

最初に作ったのがこれ。

class String
  def cntString(word)
    ary = self.split('')
    cnt = ary.count("#{word}")
    puts "'#{word}': " + "*" * cnt
  end
end
str = "Ruby is an object oriented programming language"
str.cntString(' ')
str.cntString('R')

引数に指定した文字がいくつ含まれているかを表示する、cntString メソッドを String クラスに作ってみたものの形式がだいぶ違うのでボツ。

次に作ったのがこれ。

class String
  def cntStringKai
    alpha = "abcdefghijklmnopqrstuvwxyz "
    alphaAry = alpha.split('')
    alphaCapAry = alpha.strip.upcase.split('')
    ary = self.split('')
    alphaCapAry.size.times do |i|
      cnt = ary.count("#{alphaCapAry[i]}")
      puts "'#{alphaCapAry[i]}': " + "*" * cnt if cnt >= 1
    end
    alphaAry.size.times do |i|
      cnt = ary.count("#{alphaAry[i]}")
      puts "'#{alphaAry[i]}': " + '*' * cnt if cnt >= 1
    end
  end
end
str = "Ruby is an object oriented programming language"
str.cntStringKai

絶対もっといいやり方ある(確信)。アルファベットの配列つくるとことか。 模範解答みたいに、ハッシュ使ってキーと値に分けて考えるとかなりすっきりするということはこの本やって初めて気づいた点です。

(6)

難しすぎて断念。。。
似たような問題はプログラミング入門 - Rubyを使って -, by Chris Pine, 日本語ver. by S. Nishiyamaのチャプター8でやったのですが、なにせ漢字で桁を判断したり云々という部分がわけわかめで時間かかりすぎてしまったのでスルーしました(;´Д`)
いつかリベンジしてやりたいと思います。

『たのしいRuby 第4版』 第13章 配列(Array)クラス

第13章 配列(Array)クラス

模範解答はこちら

(1)

問題

1から100までの整数が昇順に並ぶ配列を作れ、という問題です。

私的解答
a = []
100.times { |i|
  a << i + 1
}
p a

模範解答にあるように to_a メソッドを使うのも簡単でいいですね。

(2)-1

問題

(1)の配列の各要素を100倍にした新しい配列を作れ、という問題です。

私的解答
a = (1..100).to_a
a2 = []
a.each do |i|
  a2 << i * 100
end
p a2

模範解答にあるように collect メソッドを使った方がより綺麗です。。。

(2)-2

問題

新しい配列を作らずに、(1)の配列の各要素を100倍にしろ、という問題です。

私的解答
a.each_with_index do |value, i|
  a[i] = value * 100
end
p a

同上。
なぜこのような書き方になったのか(笑)

(3)-1

問題

(1)の配列から3の倍数だけを取り出した新しい配列を作れ、という問題です。

私的解答
a = (1..100).to_a
a3 = []
a.each do |i|
  a3 << i if i % 3 == 0
end
p a3

3の倍数とは3で割って余りが0の数のことなので % を使えばいいですね。

(3)-2

問題

新しい配列を作らずに、(1)の配列を3の倍数だけ取り出した配列にしろ、という問題です。

#

a.delete_if {|i| i % 3 != 0 }
p a

私的解答で使った delete_if メソッドと、模範解答にある reject! メソッドは同じ動作をするが、その戻り値だけ異なる。
delete_if メソッドは常にレシーバ自身を返す。
reject! メソッドは削除が行われたときだけレシーバ自身を返し、変化がなかったときはnilを返す。
以上のような違いがあるので、使い方に気をつけたいです。

(4)

問題

(1)の配列を逆順に並べ替えろ、という問題です。

私的解答
a = (1..100).to_a
a.reverse!
p a

この問題はシンプルに reverse! メソッドを使いました。

(5)

問題

(1)の配列の総和を求めろ、という問題です。

私的解答
a = (1..100).to_a
sum = 0
a.each do |i|
  sum += i
end
p sum

模範解答とずばりでしたが、ブロックの扱いに気をつけたいです。
基本的には、一行で書けるときは可読性を上げる意味でも、 {} を使いたいですね。

(6)

問題

(1)の配列から、1~10,11~20,21~30といった具合に10個の要素を含む配列を10個取り出し、その配列を順番に別に配列に格納しろ、という問題です。

私的解答
ary = (1..100).to_a
result = Array.new
10.times do |i|
  result << ary[i*10, 10]
end
p result

ary[n, m]とすると、nは先頭のインデックスを指し、m は必要な要素数を指します。

(7)

問題

数値からなる配列 nums1 と nums2 に対して、それらの個々の要素を足しあわせた要素からなる配列を返すメソッド sum_array を定義しろ、という問題です。

例: p sum_array([1, 2, 3], [4, 6, 8]) #=> [5, 6, 11]

私的解答
def sum_array(nums1, nums2)
  result = []
  nums1.zip(nums2) do |a, b|
    result << a + b
  end
  result
end
p sum_array([1, 2, 3], [4, 6, 8])

zip メソッドを使うことで容易に作ることが出来ました。

『たのしいRuby 第4版』第12章 数値(Numeric)クラス

第12章 数値(Numeric)クラス

模範解答はこちら

(1)

問題

摂氏温度を華氏温度に変換する cels2fahr メソッドを定義しろ、という問題です。

私的解答
def cels2fahr(cels)
  fahr = (9.0 / 5.0) * cels + 32.0
  fahr.to_f
end
1.upto(100) do |i|
  puts cels2fahr(i)
end

模範解答にもある通り、途中の計算結果が浮動小数点数になるように公式の数値を9.0などにするのがポイントかと思います。

(2)

問題

さっきとは逆に、華氏温度を摂氏温度に変換する fahr2cels メソッドを定義しろ、という問題です。

私的解答

def fahr2cels(fahr)
  cels = (5.0 / 9.0) * (fahr - 32.0)
  cels.to_f
end
puts fahr2cels(32)

ポイントは(1)と同じ。

(3)

問題

サイコロを振って出た目を返す dice メソッドを定義しろ、という問題です。

私的解答
def dice
  rand(6) + 1
end
puts dice

0から引数にとった値の手前までの乱数を発生させる rand メソッドを使います。

(4)

問題

サイコロを10回振って出た目の合計を返す dice10 メソッドを定義しろ、という問題です。

私的解答
def dice10
  total = 0
  10.times do
    me = rand(6) + 1
    total += me
  end
  total
end
puts dice10

模範解答は(3)で作った dice メソッドを流用しているのでもっと短かったです。

しかし、サイコロの目だからといって変数名を me にするこのセンスをどうにかせねば。。。

(5)

問題

与えられた引数が素数であるかどうかを調べる prime? メソッドを定義しろ、という問題。

私的解答

と行きたいところですが、あまりの難しさに禿げ上がりそうになったので断念してしまいました。。。

以下、模範解答コピペ

def prime?(num)
  return false if num < 2
  2.upto(Math.sqrt(num)) do |i|
    if num % i == 0
      return false
    end
  end
  return true
end

この問題は、平方根が用いられていることからも高度な数学的知識を要求する問題であろうことが推察されます。

・・・ん?そーでもないのかな?(笑)

『たのしいRuby 第4版』やった

久しぶりのブログ更新であります。

前々から気になっていた『たのしいRuby』を読んでみました。

入門書という位置づけではありますが、深く読み込むと知っていた知識のさらに向こう側(?)みたいな情報もたくさんあって得ることが多かったです。

で、第3部から主要なクラスについての詳しい説明が始まり、各章の終わりに練習問題があったのでやってみましたが、難易度の高いのもあったので一筋縄ではいかず、結構時間かかってしまいまいした。。。

とりあえず、Github に私的回答集を置いてみました。gotagotagoat/interestingRuby

がしかし、コードだけでは味気ないので、何回かに分けて各章の私的解答をここでさらしながらコメント的なことをしようという企画が自分のなかで持ち上がりました。

まとめてやってから書くので、当時の状況を思い出しながらの作業になり、ちょいちょい忘れてる箇所もあって後悔しながら記事をまとめていこうと思いますー。

Haml使い方メモ

ドットインストールにてHamlを勉強したので自分用メモ。

Hamlとは

HTML Abstraction Markup Language の略。

基本的な使い方としては、

  • %のあとにタグ -> 開始タグと終了タグが生成

  • インデントで入れ子構造になる

  • rubyっぽい書き方で属性を指定

%html{:lang => "ja"}

てなところ。

コメントの書き方

  • htmlにも反映したい場合 / コメント
    /
    コメント
    コメント
    コメント

  • htmlには反映したくない場合 -# コメント
    -#
    コメント
    コメント
    コメント

htmlに一行で出力する

%p hello スペースを開けて、一行で書く

hamlでだけ改行して、htmlでは改行したくない場合

    %ul
      %li<
        item
    %ul
      %li<>
        item

こうすると親要素の改行もとってくれる。

属性の指定(div)

%div{:id => "main", :class => "myClass"}

%div#main.myClass

#main.myClass
は同じ。

idとclassはよく使うのでショートカットが用意されている。 さらに、divもよく使うので省略が可能。

cssjavascripthaml内に記述する方法

:css
  .myStyle {
    color: red;
      }

このようにフィルターを利用する。

  • 便利なフィルター :escaped実体参照をしてくれる。

rubyの式を評価

%p total is #{5 * 3} #=> <p>total is 15</p>
%p= Time.now #=> <p>2014-06-05 20:25:19 +0900</p>

ただ単にrubyの命令を実行したい場合は - (マイナス)をつける。

- x = 5
%p= x #=> <p>5</p>

sqlite3について

ドットインストールでsqlite3について学んだので自分用メモ。

データベース用語

データベース: アプリごとに作るデータがはいったもの

テーブル: ユーザーテーブル、 レッスンテーブル

フィールド/カラム: 列
レコード: 行

データベースの作成

sqlite3 [データベース名].sqlite3

データベースの削除

ファイル自体を削除すればおk

sqliteの基本的な使い方

終了の仕方

.exit

helpの出し方

.help

外部ファイルの読み込み

.read [ファイル名]

テーブルの作成

create table [テーブル名] ([カラム名1], [カラム名2]);

作成済みテーブルの確認

.tables

テーブルの構造を見る

.schema [テーブル名]

テーブルの削除

drop table [テーブル名];

テーブル名の変更

alter table [旧テーブル名] rename to [新テーブル名];

カラムの追加

alter table [テーブル名] add column [カラム名];

データ型の指定について

NULL
INTEGER 整数値
REAL 少数の入った数値(浮動小数点型)
TEXT 文字列
BLOB (Binary Large OBject)

create table users (name text, email text);

  • データ型は指定できるが必須ではない。
  • データ型を指定するとそれになるように努力するが、確約はしない。

テーブル作成時のオプション

  • 自動連番の整数値をつける
    id integer primary key autoincrement

  • null値を拒否する
    not null

  • 重複した値を拒否する
    unique

  • デフォルト値を指定する
    default [値]


create table users (id integer primary key autoincrement, name text not null, email text unique, age integer default 20);

  • チェック機能を含める
    create table lessons (title, count_lessons check(count_lessons>0));
    -> count_lessonsが1以上であることをチェックする

  • インデックスを付ける
    create index [インデックス名] on [テーブル名] (カラム名);

テーブルにデータを挿入する

insert into [テーブル名] ([カラム名]) values ([値])


insert into users (name, email, age) values ('example', 'example@example. com', 20)

  • シングルクォーテーションのエスケープ
    insert into users (name, email, age) values ('it''s a pen', 'example@example.com', 20) -> '' と連続で打つ

  • null値で指定
    insert into users (name, email, age) values ('it''s a pen', 'example@example.com', null) -> null とそのまま打つ

データを更新する

update [テーブル名] set [カラム名] = [新データ] where [カラム名] = [旧データ];

データを削除する

delete from [テーブル名] where [場所の指定];

ROWIDについて

内部的に行番号を振ってくれているので便利だよ
-例
-- select ROWID, * from users;

組み込み関数

全件取得

select * from [デーブル名];

件数の取得

select count(*) from [テーブル名];

カラムの最大値の取得

select max([カラム名]) from [テーブル名];

カラムの最小値の取得

select min([カラム名]]) from [テーブル名];

乱数の表示

select random();


  • -- select * form [テーブル名] order by random() limit1;
    --> ランダムに1つのデータを選び出すときに使える

文字列の長さを表示する

select length([カラム名]) from [テーブル名];

型を明示的に表示する

select typeof(カラム名) from [テーブル名];

ユニークな値を取得する

select distinct [カラム名] from [テーブル名];

値を集計する

select sum([カラム名1]) from [テーブル名] group by [カラム名2];

現在時刻を取得する

select current_time;

現在日付を取得する

select current_date;

現在日付時刻を取得する

select current_timestamp;

-例
-- insert into users (name, created) values ('example', current_timestamp) ; --> 作成時刻を追加できる

日付に関する出力フォーマットを変更する

--例) 日本語で年を出力する
select strftime('%Y年', current_timestamp);
詳しくはリファレンスをば。

rbenv と bundler で rails 環境構築メモ

rbenv と bundler を使って既存のruby環境汚さず rails環境を構築する際の私的メモ。

ローカルインストールしたい rails のバージョンを Gemfile に記載する

作業ディレクトリに移動した後、以下のコマンドを実行し、Gemfile を作成する。

$ cat << EOS > Gemfile  
source "https://rubygems.org"  
gem "rails", "~> 3.2.0" # ←ローカルインストールしたいRailsのバージョンを指定。指定しなければ最新版が入る。  
EOS  

railsvendor/bundle 以下にインストールする

$ bundle install --path vendor/bundle

すると

Retrying dependency api due to error (2/3): Bundler::HTTPError Network error while fetching https://bundler.rubygems.org/api/v1/dependencies?gems=bcrypt,abstract,mime-types,tlsmail,treetop,hoe,ZenTest,RubyInline,test-spec,camping,fcgi,mongrel,ruby-openid,thin,multimap,tilt,hike,text-hyphen,atomic

なんかこんなかんじのエラーメッセージを吐き腐るのだが、ググれどもググれども解決策らしきものがでてこないが、特に問題なさそうなのでいったん放置。
どなた様か原因がわかる方いらっしゃいましたらぜひご一報をば・・・。

  • --path [dir] オプションを指定して bundle install を実行すると、次回以降の bundle install 時にはディレクトリ指定をしなくてもそのディレクトリが使用される

  • オプション指定をせず、単に bundle install とすると、system または、 rbenv で指定された標準の位置にインストールされてしまうので注意

rails プロジェクトを作成する

今回は example という名前で作成。
$ bundle exec rails new example --skip-bundle
--skip-bundle を指定しないと、system環境にgemがインストールされてしまうので注意

test-unitを組み込みたくない場合は以下のオプションを指定する。
$ bundle exec rails new example --skip-bundle -T

rails をローカルインストールするために使った bundler の環境を削除する

$ rm -f Gemfile
$ rm -f Gemfile.lock
$ rm -rf .bundle
$ rm -rf vendor/bundle

rails プロジェクトの環境セットアップ

先ほど作成した rails プロジェクトディレクトリに移動した後、Gemfileを編集する。

rspec を使う場合は Gemfile に以下を記載する。

gem 'rspec'  
gem 'rspec-rails'  

Gemfile を編集後、gem群をインストールする。
$ bundle install --path vendor/bundle

その後
$ bundle exec rails g rspec:install
rspec 設定ファイルを生成する。
こうすることで、新しいコンロトーラーやモデルを生成した場合に、自動的にひな形となる spec を生成してくれるので便利。

ついでに Git の管理対象から vendor/bundle ディレクトリを外す。
$ echo '/vendor/bundle' >> .gitignore

rails が本当に起動できるかを以下のコマンドで確認すると良い
$ bundle exec rails server

参考URL

http://memo.yomukaku.net/entries/IpCSQmo
http://qiita.com/emadurandal/items/a60886152a4c99ce1017#2-7
http://blog.44uk.net/2012/07/31/rails3-rspec-try-unit-test/