カテゴリー別アーカイブ: Ruby

ruby

rubyでformを取得する【サンプル】

railsのようなフレームワークを使わずに、ruby単体でform(リクエスト)情報を取得する方法です。

現在のバージョン ruby 2.1 で動作確認を行っております。

rubyでformを取得する

cgiクラスを読込んで、cgi.newするだけで使えるので簡単です。
簡単ですが、少し気を付けたい点です。
・postもgetも、同じコードで取得できるので、意図しないgetに注意する。
・checkboxやname名が同じ要素等は、配列として渡されます。params(ハッシュに変換するメソッド)を使用してアクセスすると便利です。
・escapeHTMLメソッドで、エスケープする(XSS:クロスサイトスクリプティング対策)。

もちろん、実際に使用するときは、入力値のバリデーションも行いましょう。

require "cgi"
cgi = CGI.new

# リテラルの場合
# <input type="text" name="name" />
print cgi['name']

# 配列で渡される値の場合
# <input type="checkbox" name="checkbox" value="box1" />
# <input type="checkbox" name="checkbox" value="box2" />

# 個別にアクセス
print cgi.params['checkbox'][0]

# each でまとめてアクセス
objCgi.params['checkbox'].each do |i|
  print i,"<br>"
end

# エスケープ
print CGI.escapeHTML(cgi['name'])

rubyでformを取得するサンプル

railsのようなフレームワークを使わずに、ruby単体でリクエスト情報を取得するサンプルです。
rubyでformを取得する【サンプル】
#!/xxxx/lib/ruby の部分は環境に合わせて変更してください。

#!/xxxx/lib/ruby

require "cgi"
objCgi = CGI.new

# リクエストを、エスケープし, 文字列は文字列化, 数値は数値化
# objCgi : CGIインスタンス
# arrkeys : 配列のキー(チェックボックス等)
def requestParse(objCgi, *arrkeys)
  
  require "cgi"
  hashResult = Hash.new
  
  arrRequestKeys = objCgi.keys
  
  arrRequestKeys.each do |key|
    if (arrkeys.index(key) == nil) then
      temp = CGI.escapeHTML(objCgi[key].to_s.strip)
      if ( /^([0-9])+$/ =~ temp ) then
        temp = temp.to_i
      end
    else
      # 配列の時
      arrValue = objCgi.params[key]
      temp = Array.new
      arrValue.each do |value|
        val = CGI.escapeHTML(value.to_s.strip)
        if ( /^([0-9])+$/ =~ val ) then
          val = value.to_i
        end
        temp << val
      end
    end
      hashResult[key] = temp
  end
  
  return hashResult 
end

# リクエスト(post,get)と、配列のネームを渡します。
arrRequests = requestParse(objCgi, "checkbox", "checkbox2")

# チェックボックス判定
def checkflag(array, value)
  check = ""
  if (array.class == Array and array.index(value) != nil) then
      check = "checked"
  end
  return check;
end

print <<"HERE"
Content-Type: text/html

<!DOCTYPE html>
<html lang="ja" xml:lang="ja">
<head>
    <meta charset="UTF-8">
    <title>rubyでformを取得する【サンプル】</title>
</head>
<body>
<form action="#" method="post">
    <p>name : val1</p>
    <input type="text" name="val1" value="#{arrRequests['val1']}" />
    <p>name : val2</p>
    <input type="text" name="val2" value="#{arrRequests['val2']}" />
    <p>name : radio</p>
    <input type="radio" name="radio" value="radio1" #{ "checked" if arrRequests["radio"] == "radio1"} />radio
    <input type="radio" name="radio" value="radio2" #{ "checked" if arrRequests["radio"] == "radio2"} />radio2
    <input type="radio" name="radio" value="radio3" #{ "checked" if arrRequests["radio"] == "radio3"} />radio3<br />
    <br />
    <p>name : checkbox</p>
    <input type="checkbox" name="checkbox" value="momo" #{checkflag(arrRequests["checkbox"], 'momo')} />momo
    <input type="checkbox" name="checkbox" value="hana" #{checkflag(arrRequests["checkbox"], 'hana')} />hana
    <input type="checkbox" name="checkbox" value="kuri" #{checkflag(arrRequests["checkbox"], 'kuri')} />kuri
    <input type="checkbox" name="checkbox" value="2929" #{checkflag(arrRequests["checkbox"], 2929)} />2929<br />
    <br />
    <p>name : checkbox2</p>
    <input type="checkbox" name="checkbox2" value="1" #{checkflag(arrRequests["checkbox2"], 1)} />1
    <input type="checkbox" name="checkbox2" value="2" #{checkflag(arrRequests["checkbox2"], 2)} />2
    <input type="checkbox" name="checkbox2" value="3" #{checkflag(arrRequests["checkbox2"], 3)} />3
    <input type="checkbox" name="checkbox2" value="4" #{checkflag(arrRequests["checkbox2"], 4)} />4<br />
    <br />
    <p>name : textbox</p>
    <textarea name="textbox" rows="10" cols="50">#{arrRequests['textbox']}</textarea>
    <br />
    <input type="submit" name="submit" value="送信" />
</form>
HERE

print "</body></html>\n"

オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル

オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル

ruby

ruby 関数定義 メソッド引数「*」が空の時

下記の関数「foo3」について
foo3に、引数を一つ渡した場合、arrの形が知りたかったので、関数定義についてまとめました。
結果は、配列として帰ってきていました。

関数の作り方:基本

# 基本
def foo(name)
  puts name
end

# 初期値
def foo2(name = "momo")
  puts name
end

# 引数の数を不定
def foo3(a, *arr)
  print [a, arr]
end

# 引数の数を不定 ver2
def foo4(a, *arr, b)
  p a, arr, b
end


foo("hogehoge") # => hogehoge

foo2() # => momo
foo2("hogehoge") # => hogehoge

foo3(1) # => [1, []]
foo3(1, 2, 3, 4, 5) # => [1, [2, 3, 4, 5]]

# foo4(1) # エラー
foo4(1, 2, 3, 4, 5) # => [1, [2, 3, 4], 5]

関数の作り方:ハッシュ引数

# 引数にキーワード
def foo5(x: 0, y: 0, z: 0)
  print "x:", x,"  y:", y,"  z:", z
end

# 引数にキーワード(配列)
def foo6(x: 0, y: 0, z: 0)
  p x[1]
end

# 引数にキーワード(配列)
def foo7(x: 0, y: 0, z: 0, **arr)
  p [x, y, z, arr]
end


foo5(y: 2, x: 1, z: 3) # => x:1  y:2  z:3
foo5(y: 4) # => x:0  y:4  z:0

foo6(x: [5, 6]) # => 6

foo7(x: 2, v: 3, z: 4, w: 5) # => [2, 0, 4, {:v=>3, :w=>5}]

書籍 たのしいRuby 第4版

google_chrome-410x230

chromeで、Content-Type の調べ方

『Content-Type』を調べたい事がありましたので、調べ方をメモしておきます。

chromeで、Content-Type の調べ方

Content-Type について

その前に、『Content-Type』について復習です。

たとえば、インターネットでファイルのダウンロードを行う時等、ファイルに拡張子がなかったり、拡張子からファイルの種類が分からない場合がある。
その場合、「これから返すファイルの種類」をContent-Typeによって示すことで、ファイルの種類を受け取る側が知ることができる。またその種類に応じて、Webブラウザがそのまま表示したり、ファイルとして保存したり、他のアプリケーションを起動してそれを用いて出力したり、と処理を変更する。

Content-Typeとは : JavaA2Z

簡単に言うと、windowsでの拡張子に当たる部分です。
例えば、ブラウザでweb上の『.cgi』ファイルにアクセスした場合、拡張子からCGIだとわかっても、帰ってくるデータが、テキストなのか、画像なのか、scriptなのか、ダウンロードファイルなのか、ブラウザは分からは判断できません。したがって、『Content-Type』にファイル形式を明示するのです。

今までコードのお約束事として記述していた下記のような『Content-Type』は、「htmlファイルです」と、ブラウザに伝えていたのです。(HTML5からは記述しなくても、”text/html”として扱われるようです。)

# HTML
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
# php
header("Content-type: text/html; charset=utf-8");

Content-Type を調べてみる。

本題です。実際にheader情報の『Content-Type』をchromeを使って確認してみます。
chormeのアドレスバーに

chrome://net-internals/#events

を、入力します。(chrome://about/ と入力すると、開発者向けの機能が提供されています。その中の1つです。)

chrome_net-internals01

表示されたリストから、確認したい通信をクリックします。
当サイトだと、
Source Type : URL_REQUEST
Description : http://blog.cototoco.net/
です。ウィンドウ右側に詳細が表示されます。

詳細の中、さらに、HTTP_TRANSACTION_READ_RESPONSE_HEADERS、に『Content-Type』が記載されています。

chrome_net-internals02

当サイトの『Content-Type』が
Content-Type: text/html; charset=UTF-8
だとわかります。

実験

html5に『Content-Type』(metaタグ)有り無しで実験してみます。ちなみに、HTML5では省略しても”text/html”と扱われるので、省略しています。

# meta 有り無し
<meta http-equiv="content-type" content="text/html" charset="UTF-8">

html5に『Content-Type』有りの場合

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="content-type" content="text/html" charset="UTF-8">
<title>Content-Typeサンプル</title>
</head>
<body>
<p>HTML5 Content-Type はどうなっているか?</p>
</body>
</html>

html5に『Content-Type』有りの場合の『Content-Type』は
Content-Type: text/html となっていることが確認できました。

# meta 有りのheader情報
HTTP_TRANSACTION_READ_RESPONSE_HEADERS
--> HTTP/1.1 200 OK
  Date: Fri, 11 Jul 2014 05:27:51 GMT
  Server: Apache
  Last-Modified: Fri, 11 Jul 2014 05:27:41 GMT
  ETag: "5e1f2e-e8-53bf75cd"
  Accept-Ranges: bytes
  Content-Length: 232
  Connection: close
  Content-Type: text/html

html5に『Content-Type』無しの場合

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Content-Typeサンプル</title>
</head>
<body>
<p>HTML5 Content-Type はどうなっているか?</p>
</body>
</html>

html5に『Content-Type』有りの場合の『Content-Type』は
明記されていないようです。(注:キャッシュが残っている場合はキャッシュが表示されているようです。)

# meta 無しのheader情報
HTTP_TRANSACTION_READ_RESPONSE_HEADERS
--> HTTP/1.1 304 Not Modified
   Date: Fri, 11 Jul 2014 05:38:35 GMT
   Server: Apache
   Connection: close
   ETag: "5e1f2e-a2-53bf782f"

以上、chromeで、Content-Type の調べ方です。
また、この方法で、header情報も同時に確認できることになります。

Content-Typeとは : JavaA2Z

gihyo.jp

ruby

ディープコピー 【Ruby】

『オブジェクトのコピー』,『メソッドの引数(値渡し、参照渡し)』の延長です。私もよくわかっていないので、さらっと流します。

配列のコピーや、メソッドの引数に配列を渡すとき、『副作用』(コピー先の値を変更すると、コピー元の値も変更される)が発生するので、『副作用』を避ける場合、cloneメソッドで複製を作る方法を紹介しました。

しかし、多重ループの場合 cloneメソッドでは、2次以上の部分に副作用が残ります。その際に用いるのが、ディープコピー(deep copy)という方法です。

Javaではキチンと?書かないといけないようですが、rubyでは次のコードでディープコピー行えるようです。(*2)

obj_m = Marshal.load(Marshal.dump(obj))

Marshalモジュール : オブジェクトをファイル(または文字列)に書き出したり、読み戻したり する機能を提供するモジュール(*1)
渡したオブジェクトを、Marshal.dump で出力し、Marshal.loadで読み込み、オブジェクトを返すイメージです。

実際にサンプル(sample01)を見てみます、まず clone メソッドでコピーした場合の副作用を見てみます。
4, 5行目 : clone で複製したオブジェクトは別物になっています。
しかし、
6, 7行目 : arrA[0]と、arrB[0]は同じオブジェクトを参照
8, 9行目 : arrA[1]と、arrB[1]は同じオブジェクトを参照
しているので、arrA[0][1]の値を変更した際に、arrBの中の値も変更されています(副作用)。

arrA = Array.new(2){ |i| Array.new(4){ |j| i * 4 + j + 1 } }
p arrA # => [[1, 2, 3, 4], [5, 6, 7, 8]]
arrB = arrA.clone
p arrA.object_id # => 17481360
p arrB.object_id # => 17481200
p arrA[0].object_id # => 17481350
p arrB[0].object_id # => 17481350
p arrA[1].object_id # => 17481340
p arrB[1].object_id # => 17481340
arrA[0][1] = 10
p arrA # => [[1, 10, 3, 4], [5, 6, 7, 8]]
p arrB # => [[1, 10, 3, 4], [5, 6, 7, 8]]

ディープコピーを使ったサンプル(sample02)では、
6, 7, 8, 9行目 : arrA[0], arrB[0], arrA[1], arrB[1] が、それぞれ別々のオブジェクトを参照しています。
arrA[0][1]の値を変更しても、arrBの中の値は変更されていません。

arrA = Array.new(2){ |i| Array.new(4){ |j| i * 4 + j + 1 } }
p arrA # => [[1, 2, 3, 4], [5, 6, 7, 8]]
arrB = Marshal.load(Marshal.dump(arrA))
p arrA.object_id # => 7977880
p arrB.object_id # => 7977670
p arrA[0].object_id # => 7977870
p arrB[0].object_id # => 7977660
p arrA[1].object_id # => 7977860
p arrB[1].object_id # => 7977650
arrA[0][1] = 10
p arrA # => [[1, 10, 3, 4], [5, 6, 7, 8]]
p arrB # => [[1, 2, 3, 4], [5, 6, 7, 8]]

蛇足で、3次元配列もディープコピーを見てみますと、別々のオブジェクトを参照しているようです。

arrA = Array.new(3){ |i| Array.new(2){ |j| Array.new(3){|k| i * 6 + j * 3 + k + 1 }} }
p arrA # => [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]]]
p arrA[0] # => [[1, 2, 3], [4, 5, 6]]
p arrA[0][0] # => [1, 2, 3]
arrB = Marshal.load(Marshal.dump(arrA))
p arrA.object_id # => 17830590
p arrB.object_id # => 17830150
p arrA[0].object_id # => 17830580
p arrB[0].object_id # => 17830140
p arrA[0][0].object_id # => 17830570
p arrB[0][0].object_id # => 17830130

(*1)Ruby 2.1.0 リファレンスマニュアル module Marshal

(*2)Ruby 1.8.7 リファレンスマニュアル instance method Object#clone

ruby

メソッドの引数(値渡し、参照渡し)

Rubyの引数は値渡しです。

Rubyの引数は値渡しです。参照渡しではありません。ググるとそのようにまとめてらっしゃる方が多々ありますので間違いはないとおもいます。Ruby リファレンスマニュアルで探してみたんですが、記載を見つけられませんでした、確認でき次第アドレスを掲載します。
(*1)参考リンクを追加しました。

ここではRubyの引数(値渡し,参照渡し)について自分なりにまとめてみます。

Rubyist Magazine – 値渡しと参照渡しの違いを理解する

を深く読んでください。を深く読んでください。を深く読んでください。
この記事よりもよっぽど詳しいです。。。

メソッドの復習と名称

def hoge(a) # メソッド: hoge, 仮引数: a
    a += 10 # a に 10 を足す
end

x = 10 # 変数 x
hoge(x) # メソッド hoge に、実引数 x を渡す

値渡しと参照渡し

値渡しと参照渡しについて簡単に説明します。詳細は本当にググってください…

・値渡し (call by value) :実引数として変数を渡しても、その値のみが渡される。そのため、仮引数を変更しても、実変数は変更されない。

def hoge(a) # メソッド: hoge, 仮引数: a
    a += 10 # a に 10 を足す
    p a # => 20
end

x = 10 # 変数 x
hoge(x) # メソッド hoge に、実引数 x を渡す
p x # => 10

・参照渡し (call by variable) :実引数として変数を渡しすとき、変数に対する参照(メモリ番地)先を渡す。そのため、仮引数の値を変更すると、実変数の値も同様に変更されたことになる。

def hoge(a) # メソッド: hoge, 仮引数: a
    a += 10 # a に 10 を足す
end

x = 10 # 変数 x
hoge(x) # メソッド hoge に、実引数 x を渡す
p x # => 20

注)仮のコードです、rubyでは動作確認できません

引数(実引数)が配列の場合

Rubyは『値渡し』です。しかし、実引数にが配列の場合『参照渡し』のような結果になるときがあります。実引数で渡した配列が、仮引数の値を変更すると実引数の値も変わってしまう『副作用』が生じます。実はこの時『参照の値渡し』と言う値渡しが行われています。
理屈は以前の記事オブジェクトのコピーと同じで、実引数も仮引数も同じオブジェクトを見ている、仮引数にはオブジェクトの参照の値が渡されたということになります。

def hoge(a) # メソッド: hoge, 仮引数: 配列 a
    a[0] += 10 # 配列a[0] に 10 を足す
end

x = [10] # 変数: 配列 x
hoge(x) # メソッド hoge に、実引数 x を渡す
p x # => [20] # 実引数の値が変更されている

objcet_idを確認してみる

def hoge(a)
    a[0] += 10
    p a.object_id # => 17968120
end

x = [10]
p x.object_id # => 17968120
hoge(x)
p x # => [20] # 実引数の値が変更されている

*)object_idで同一性を確認しているだけです。rubyではメモリの番地を調べることはできないようです。

引数(実引数)が配列の場合の『副作用』を予防する

この副作用を予防するには、実引数と仮引数が別のオブジェクトを参照していれば良いということになります。なので、複製を作ればOKになります。

def hoge(a)
  p a.object_id # => 540724920
end

x = [1, 2, 3, 4, 5]
p x.object_id # => 539436540
temp = x.clone
hoge(temp)
def hoge(*a) # * 複数の引数を配列として受け取ります。
  p a.object_id # => 539428060
end

x = [1, 2, 3, 4, 5]
p x.object_id # => 539443780
hoge(*x) # * 展開して渡します

sample01, sample02 もobject_idが違うので、『副作用』は起こりません。

しかし・・・多重配列だと・・・別の機会追記しました。

Rubyist Magazine – 値渡しと参照渡しの違いを理解する

引数 – Wikipedia

*1)お気楽 Ruby プログラミング入門第 3 回●値呼びと参照呼び

変数や定数は,あるオブジェクトを指しています.何も代入しなくても nilオブジェクトを指しています.代入は,変数や定数が新しいオブジェクトを 指すようにします.

したがって,代入によりオブジェクトがコピーされて新しく作られることは なく,右辺の表現の表しているオブジェクトを左辺の変数や定数が指すように することが代入によって行われます.

*1)Ruby FAQ: 変数,定数,引数(文字化けします、EUCで開いてください)