aws-sdkを使ってAmazon S3を操作する

ちょっと間が開いたけど、インストールした aws-sdk を使ってみた。

created-bucket

まずはバケットを作る。aws-sdk を使ってもできるけど、ブラウザからやった。これがバケットを作ったところ。見難い(てか見えない)けど panicblanet ていうバケットができている。

次に、API にアクセスするための Access Key ID と Secret Access Key を取得する。これは右上の自分の名前が書いてあるところをクリックすると現れるプルダウンメニューから Security Credentials を選ぶと、キーを作れるページに移動するのでそこで作る。詳しくは書かないけど難しくはない。

さて、これで準備が整った。それじゃ最初はファイルをアップロードするスクリプトから行こう。

require 'aws'
require 'yaml'

config = YAML.load_file("aws-config.yaml")

file = ARGV.shift
key = ARGV.shift
content = File.open(file, "rb"){|f| f.read}

s3 = AWS::S3.new(
  :access_key_id     => config["ACCESS_KEY_ID"],
  :secret_access_key => config["SECRET_ACCESS_KEY"])

bucket = s3.buckets["panicblanket"]
obj = bucket.objects[key]
if obj.exists?
  puts "Error: Object already exists: #{key}."
  exit
end
obj.write(content, :acl => :public_read)

キーをハードコードするのはアレなので aws-config.yaml ファイルから読み込むようにした。早速試してみよう。

^o^ > ruby s3_upload_file.rb Penguins.jpg Penguins.jpg
uploaded_object

何も出力されないのはうまくいったからのはずだ。ブラウザで確認してみると、ちゃんとアップロードされているのがわかる。

penguins

アクセスコントロールに :public_read を指定しているので、誰でもブラウザで見られるはずだ。URL は http://panicblanket.s3.amazonaws.com/Penguins.png。

うん、うまくいってる。

バケットの中のオブジェクトを指定するキーはディレクトリ風にもできる。こんなふうに。

^o^ > ruby s3_upload_file.rb Penguins.jpg data/Penguins.jpg

それじゃ次はバケットに保存されているオブジェクトのリストを取得してみる。

require 'aws'
require 'yaml'

config = YAML.load_file("aws-config.yaml")

s3 = AWS::S3.new(
  :access_key_id     => config["ACCESS_KEY_ID"],
  :secret_access_key => config["SECRET_ACCESS_KEY"])

bucket = s3.buckets["panicblanket"]
bucket.objects.each do |obj|
  puts obj.key
end
^o^ > ruby s3_list_objects.rb
Penguins.jpg
data/Penguins.jpg

上でアップロードした2つのオブジェクトが表示された。

つぎ、ダウンロード。

require 'aws'
require 'fileutils'
require 'yaml'

config = YAML.load_file("aws-config.yaml")

key = ARGV.shift

s3 = AWS::S3.new(
  :access_key_id => config["ACCESS_KEY_ID"],
  :secret_access_key => config["SECRET_ACCESS_KEY"])

file = key
if File.dirname(file) != "."
  FileUtils.mkdir_p(File.dirname(file))
end

bucket = s3.buckets["panicblanket"]
obj = bucket.objects[key]

unless obj.exists?
  puts "Error: No such object: #{key}"
  exit
end

File.open(file, "wb") do |f|
  obj.read do |chunk|
    f.write(chunk)
  end
end
^o^ > ruby s3_download_object.rb data/Penguins.jpg

^o^ > ls data
Penguins.jpg

これもうまくいってる。よしよし。

それじゃ最後に、オブジェクトの消去。

require 'aws'
require 'yaml'

config = YAML.load_file("aws-config.yaml")

s3 = AWS::S3.new(
  :access_key_id     => config["ACCESS_KEY_ID"],
  :secret_access_key => config["SECRET_ACCESS_KEY"])
bucket = s3.buckets["panicblanket"]

key = ARGV.shift
obj = bucket.objects[key]
unless obj.exists?
  puts "No such object: #{key}"
  exit
end
obj.delete
^o^ > ruby s3_delete_object.rb data/Penguins.jpg

^o^ > ruby s3_list_objects.rb
Penguins.jpg

ちゃんと消えたようだ。

aws-sdkをgemでインストールしたらNokogiriも使えるようになった

Amazon の S3 を使ってみようと思っていろいろ調べた結果、aws-sdk という gem をインストールすればいいというのがわかったので、インストールしたら Nokogiri も一緒にインストールされた。

^o^ > gem install aws-sdk
Fetching: mini_portile-0.6.0.gem (100%)
Successfully installed mini_portile-0.6.0
Fetching: nokogiri-1.6.2.1-x64-mingw32.gem (100%)
Nokogiri is built with the packaged libraries: libxml2-2.8.0, libxslt-1.1.28, zl
ib-1.2.8, libiconv-1.14.
Successfully installed nokogiri-1.6.2.1-x64-mingw32
Fetching: aws-sdk-1.42.0.gem (100%)
Successfully installed aws-sdk-1.42.0
Parsing documentation for mini_portile-0.6.0
Installing ri documentation for mini_portile-0.6.0
Parsing documentation for nokogiri-1.6.2.1-x64-mingw32
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/nokogiri/2.0/nokogiri.
so, skipping
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/nokogiri/2.1/nokogiri.
so, skipping
Installing ri documentation for nokogiri-1.6.2.1-x64-mingw32
Parsing documentation for aws-sdk-1.42.0
Installing ri documentation for aws-sdk-1.42.0
3 gems installed

うーん、前に苦労してダメだったのはなんだったんだ。

Sinatraで”invalid byte sequence in Windows-31J”

先週に引き続き古い Web アプリを Ruby2.0 対応(一番最近のコミットが2010年の11月だった)。今回は Sinatra。
で、スクリプトのエンコードを UTF-8 にして、require 'jcode' を消して、などと一通り修正して完了。無事動くようになったんだけど、日本語を含む URL のときにタイトルのエラーが発生した。しかも、どうもアプリじゃなくて Rack の中で起きているらしい。
こんなのどうすりゃいいんだよ、と思いながらググってみたらずばりそのもののページを見つけた。

 cf. Sinatra が ”invalid byte sequence in Windows-31J” でエラーページを表示しない(@Windows) – Qiita

どうやら、Rack は外から来る文字列のエンコーディングを Encoding.default_external の値だとして変換するらしい。で、その Encoding.default_external の値が Windows-31J なわけだ。でも実際は UTF-8 の文字列だから変換中にエラーが発生する、と。

というわけで、app.rb の中に1行追加した。

Encoding.default_external = 'utf-8'


上記のページでは config.ru の中に追加してるけど、こっちのほうがいいような気がする。気のせいかもしれないけど。

さて、これでめでたく日本語が入ってても動くようになった。

RDiscountでmarkdownをためす

昔書いた CGI にちょっと手を入れたついでに、ドキュメントを Markdown に書き直そうと思って調べてみたら、Ruby では RDiscount ってのがよさそうだったので試してみた。今日はそのメモ。

拡張ライブラリが含まれているというのでちょっと心配だったけど、インストールはあっさりすんだ。

^o^ > gem install rdiscount
Fetching: rdiscount-2.1.7.1.gem (100%)
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
Successfully installed rdiscount-2.1.7.1
Parsing documentation for rdiscount-2.1.7.1
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/rdiscount.so, skipping

Installing ri documentation for rdiscount-2.1.7.1
1 gem installed

Markdown の例はこんな感じ。記法についてはググればいくらでもページが見つかるので割愛。

見出し1
========

見出し2
--------

ここは本文。

### 見出し3

見出し3以上は # を行頭につける。見出し6までいけるみたい。

### 番号なしリスト

行頭に * か - で番号なしのリストになる。

- リスト1
- リスト2
- リスト3

### 番号つきリスト

番号つきリストは行頭に 1. というふうに番号をつける。

1. リスト1
2. リスト2
3. リスト3

----

3つ以上の - で水平線。

これを HTML に変換するには、rdiscount コマンドを使えばいい。標準出力に吐き出すので、適当なファイルにリダイレクトしてやる。

^o^ > rdiscount example.md > example.html

Ruby のスクリプト内で使うには、RDiscount クラスのインスタンスを作って to_html メソッドで変換する。

require 'rdiscount'

markdown = RDiscount.new(File.open(ARGV.shift, "r"){|f| f.read})
print markdown.to_html

ま、とりあえず使うのはこんなところ。

NokogiriがダメだったのでHpricotをインストールした

タイトルのとおり。Hpricot はすんなりインストールできた。

^o^ > gem install hpricot
Fetching: hpricot-0.8.6.gem (100%)
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
Successfully installed hpricot-0.8.6
Parsing documentation for hpricot-0.8.6
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/fast_xs.so, skipping
unable to convert "\x90" from ASCII-8BIT to UTF-8 for lib/hpricot_scan.so, skipp
ing
Installing ri documentation for hpricot-0.8.6
1 gem installed

でも、もともと Hpricot を使ってたのを Nokogiri に乗り換えたんだよなあ。

一応、簡単なスクリプトを書いてちゃんと動くかどうか試してみよう。

require 'hpricot'

HTML =<<

Hello, world. This is <a href="https://blog.panicblanket.com/">blog.PanicBlanket.com</a>

EOH

doc = Hpricot(HTML)
links = doc.search("a")
puts links[0]["href"]

実行結果:

^o^ > ruby hpricot_test.rb
https://blog.panicblanket.com/

うまくいってるようだ。

Windows7のRubyにNokogiriがインストールできない

年末年始の休みも(気分的に)終わったので、Nokogiri のインストールに挑戦する。前回のエントリは MinGW をインストールしたところで終わったけど、正常にインストールできていないように見えるので不安。
で、結果から先に言ってしまうと、Nokogiri はインストールできなかった。できなかったというエントリを書く必要があるのかどうか悩むところだけど、メモのために記録を残しておく。
基本は、↓このページに沿って作業した。

 cf.WindowsのRuby 2.0でNokogiriを使う ― KaoriYa

と、その前に、gcc と sh のあるディレクトリにパスを通しておく。具体的には、C:\MinGW\bin と C:\MinGW\msys\1.0\bin にパスを通した。
でもって、msys.bat を起動して作業開始。ところが、sh ./configure のときから gcc が次のようなメッセージを出す。

nodisk

仕方がないので「続行」をクリックすると、またすぐに同じメッセージが。これを数十回も繰り返してやっと終わったと思ったら make でもやっぱり同じメッセージが数十回も出た。あー、こりゃうまくいかないな。
結局、libxml2 でも libxslt でも同じ状況で、当然 Nokogiri のインストールもうまくいかずじまい。
Ruby を使うのもだんだんつらくなってくるなあ。

Windows7にMinGWがインストールできない?

※ 追記あり

gem で nokogiri をインストールしようとしたところ、次のようなエラーが出てインストールできなかった。

^o^ > gem install nokogiri
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
ERROR:  Error installing nokogiri:
        ERROR: Failed to build gem native extension.

    C:/Ruby200-x64/bin/ruby.exe extconf.rb
checking for libxml/parser.h... no
-----
libxml2 is missing.  please visit http://nokogiri.org/tutorials/installing_nokog
iri.html for help with installing dependencies.
-----
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=C:/Ruby200-x64/bin/ruby
        --with-zlib-dir
        --without-zlib-dir
        --with-zlib-include
        --without-zlib-include=${zlib-dir}/include
        --with-zlib-lib
        --without-zlib-lib=${zlib-dir}/lib
        --with-iconv-dir
        --without-iconv-dir
        --with-iconv-include
        --without-iconv-include=${iconv-dir}/include
        --with-iconv-lib
        --without-iconv-lib=${iconv-dir}/lib
        --with-xml2-dir
        --without-xml2-dir
        --with-xml2-include
        --without-xml2-include=${xml2-dir}/include
        --with-xml2-lib
        --without-xml2-lib=${xml2-dir}/lib
        --with-xslt-dir
        --without-xslt-dir
        --with-xslt-include
        --without-xslt-include=${xslt-dir}/include
        --with-xslt-lib
        --without-xslt-lib=${xslt-dir}/lib
        --with-libxslt-config
        --without-libxslt-config
        --with-pkg-config
        --without-pkg-config
        --with-libxml-2.0-config
        --without-libxml-2.0-config
        --with-pkg-config
        --without-pkg-config
        --with-libiconv-config
        --without-libiconv-config
        --with-pkg-config
        --without-pkg-config


Gem files will remain installed in C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/nokog
iri-1.6.1 for inspection.
Results logged to C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/nokogiri-1.6.1/ext/nok
ogiri/gem_make.out

調べてみると、どうやら nokogiri はもはや Pure Ruby ではなく、おまけにほかのCライブラリに依存するらしい。
Windows の Ruby 2.0.0 に nokogiri をインストールする方法はこのページに詳しい。

 cf. WindowsのRuby 2.0でNokogiriを使う ― KaoriYa

というわけで、ここからが今日の本題。C のライブラリをビルドするためにまずは MinGW のインストールに挑戦する。
まずは、ダウンロードページから mingw-get-setup.exe をダウンロード。これを右クリックして管理者として実行する。
順調に進むかと思いきや、「”C:\MinGW\libexec\mingw-get\shlink.js” のスクリプト エンジン “JScript” が見つかりません。」というエラーがでてしまう。先週、有効にしたはずなのにおかしい。
とりあえず「OK」をクリックすると MinGW Installation Manager というパッケージ管理ツールのウィンドウが開く。ここでインストールしたいパッケージを選んで(よくわからんので Basic Setup にあるすべてを選んだ)、メニューから Installation → Apply Changes をクリックするとインストールが始まって、しばらくすると無事終わった(ように見える)。
ところが、スタートメニューにもデスクトップにもショートカットが作成されていない。これってやっぱり正常にインストールされてないってことか?

試しに簡単なプログラムを書いてみた。

#include

main () {
    printf("Hello, world.\n")
}

実行結果:

^o^ > gcc -o hello.exe hello.c

^o^ > hello.exe
Hello, world.

なんと、コンパイルができてしまった。どういうこと?

[追記]
gcc が使えたのは、MinGW が正常にインストールされているわけじゃなかった。Haskell Platform に含まれてる gcc が動いていた。

^o^ > which gcc
C:/Program Files (x86)/Haskell Platform/2012.4.0.0/mingw/bin/gcc.EXE

MinGW のほうにパスを通せばいいのかなあ。shlink.js が何をやってるのか調べてみようか。

Rubyを2.0.0にバージョンアップした

もうすぐ2.1.0も出そうだというのに、いまさらながら2.0.0にバージョンアップした。
使うのはいつものとおり、One-Click Ruby Installer for Windows。ダウンロードページから、64bit版をダウンロードした。

 cf. http://rubyinstaller.org/downloads/

インストール自体はいたって簡単なので省略。あらかじめgemもいくつかインストールされていた。

^o^ > ruby -v
ruby 2.0.0p353 (2013-11-22) [x64-mingw32]

^o^ > gem list

*** LOCAL GEMS ***

bigdecimal (1.2.0)
io-console (0.4.2)
json (1.7.7)
minitest (4.3.2)
psych (2.0.0)
rake (0.9.6)
rdoc (4.0.0)
test-unit (2.0.0.0)

ついでなので、Development Kit も入れることにする。同じページから64bit版の DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe をダウンロード。自己解凍形式のexeファイルなので、C:\DevKit に解凍した。で、あとはインストール作業。次のようにした。

^o^ > cd c:\DevKit

^o^ > ruby dk.rb init
[INFO] found RubyInstaller v2.0.0 at C:/Ruby200-x64

Initialization complete! Please review and modify the auto-generated
'config.yml' file to ensure it contains the root directories to all
of the installed Rubies you want enhanced by the DevKit.

^o^ > ruby dk.rb install
[INFO] Updating convenience notice gem override for 'C:/Ruby200-x64'
[INFO] Installing 'C:/Ruby200-x64/lib/ruby/site_ruby/devkit.rb'

これでOKかな。

Ruby でランダムな文字列を得る

昨日のやつを Ruby でもやってみた。

# coding: utf-8

def randstr(length)
  pool = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a
  r = Random.new
  l = pool.size
  rand_str = ''
  length.times do |i|
    rand_str += pool[r.rand(l)]
  end
  rand_str
end

length = ARGV.shift.to_i
print randstr(length)

実行結果:

^o^ > random_string.rb 20
y397x9Bx1z7fAvJTr9RK

Random クラスの使い方はここ:

cf. http://docs.ruby-lang.org/ja/1.9.3/class/Random.html