Hashie::Mashおかしい
(解決した、下に書いた)
これ実行すると
#!/usr/bin/env ruby require 'rubygems' require 'hashie' arr = Array.new 3.times do |i| arr.push Hashie::Mash.new(:count => i, :text => 'test'*i) end arr.each do |i| p i puts "count : #{i.count}" puts "text : #{i.text}" end
countだけ同じ値がでるんだけど、なんで・・・?
#<Hashie::Mash count=0 text=""> count : 2 text : #<Hashie::Mash count=1 text="test"> count : 2 text : test #<Hashie::Mash count=2 text="testtest"> count : 2 text : testtest
Hash#countで保持しているkeyの数が返ってくるらしい。
hashieはmethod_missingで実装されているので、missingじゃないの呼び出してた。
このへん全部使えない
1.8.7 :002 > h.methods => ["find", "[]=", "inspect", "convert_value", "merge", "tap", "reject!", "clone", "take", "store", "__send__", "object_id", "public_methods", "reject", "instance_variable_defined?", "minmax", "hashie_inspect", "freeze", "equal?", "indexes", "member?", "each", "values", "delete", "sort", "extend", "partition", "each_cons", "send", "any?", "each_with_index", "hashie_stringify_keys!", "default", "methods", "values_at", "initializing_reader", "detect", "hashie_stringify_keys", "hash", "take_while", "default=", "default_proc", "dup", "replace", "instance_variables", "to_enum", "collect", "clear", "stringify_keys", "min_by", "invert", "sort_by", "eql?", "indices", "regular_reader", "size", "has_key?", "group_by", "enum_cons", "instance_eval", "id", "one?", "enum_with_index", "singleton_methods", "find_index", "deep_merge!", "taint", "empty?", "shift", "drop", "each_value", "instance_variable_get", "frozen?", "enum_for", "map", "shallow_merge", "display", "instance_of?", "max_by", "method", "grep", "to_a", "regular_writer", "update", "first", "to_json", "has_value?", "instance_exec", "type", "fetch", "none?", "reverse_each", "stringify_keys!", "rehash", "protected_methods", "find_all", "delete_if", "regular_dup", "method_missing", "==", "min", "to_mash", "===", "drop_while", "each_key", "instance_variable_set", "shallow_update", "each_slice", "key?", "inject", "kind_of?", "minmax_by", "respond_to?", "keys", "count", "to_s", "convert_key", "value?", "class", "to_hash", "index", "zip", "private_methods", "=~", "tainted?", "__id__", "select", "deep_merge", "length", "max", "hash_inspect", "untaint", "nil?", "each_pair", "entries", "deep_update", "cycle", "merge!", "reduce", "enum_slice", "include?", "is_a?", "[]", "all?"]
idとかclassとかcountとかindexとかtypeとかmapとかmaxとかlength使えなかったとはワロタ
こうすると値を取り出せる
1.8.7 :007 > h.count = 30 => 30 1.8.7 :008 > h['count'] => 30
gemを全て新しいRubyに入れなおす
rvmで、新しいrubyに乗り換える時によくやる。
ruby-1.8.7-p352 → 1.8.7-p358にしたとする。
rvm get latest
rvm reload
rvm list known
rvm install 1.8.7-p358
gem listを保存しておいて
gem list | ruby -lane 'puts $_.split(/\s/)[0]' > ~/gems.txt
あたらしい方に入れなおす
rvm use 1.8.7-p358 cat ~/gems | xargs gem install --no-rdoc --no-ri
gem list
rvm use 1.8.7-p358 --default
そういえばrdoc、gem serverコマンドで起動するやつで見ると見やすい。
herokuセットアップ、sinatraを動かす
herokuでsinatra動かした。
参考にした
サインアップ
https://heroku.com でサインアップ、メールが来るのでconfirm
アプリを作る
普通のsinatraアプリを作ってみる。
% ls Gemfile Gemfile.lock Procfile web.rb
の4つのファイルが最終的にできる。
web.rb
require 'rubygems' require 'sinatra' get '/' do 'hello work' end
Gemfile
source :rubygems gem 'sinatra' gem 'thin'
Procfile を作る。中身はこれ
web: bundle exec ruby web.rb -p $PORT
config.ruを使うならこうらしい
web: bundle exec rackup config.ru -p $PORT
ローカルで動かしてみる
Procfileで動かすためにforemanってのを使うらしい。
gem install foreman bundle install foreman start
herokuにデプロイ
gitリポジトリにしてherokuにpushする。
git init git add Gemfile Gemfile.lock web.rb Procfile git commit -m 'first commit'
Gemfile.lockもcommitする。
heroku create --stack cedar git push heroku master
remoteにherokuが追加されているので、pushする
herokuで動いた
http://simple-mountain-9295.herokuapp.com みたいな長い名前で起動するので、 https://api.heroku.com/myapps/ で名前を変更した。
こうなった。
http://shokai.herokuapp.com/
mini_magickとImageMagickで画像を切り取る
capybara-webkitで撮影した縦長のwebページスクリーンショット(PNG)を、1:1.41のA4縦長で印刷できるサイズ(JPEG)に分割する。
brew install imagemagick gem install mini_magick
mini_magick版
#!/usr/bin/env ruby require 'rubygems' require 'mini_magick' source = ARGV.shift img = MiniMagick::Image.open source puts "#{img[:width]}x#{img[:height]}" w = img[:width] h = (w*1.41).to_i 0.upto(img[:height]/h) do |i| puts fname = "#{i}.jpg" img = MiniMagick::Image.open source img.format('jpg') img.quality('95') img.crop("#{w}x#{h}+0+#{i*h}") img.write(fname) end
結果
1236x8026 0.jpg 1.jpg 2.jpg 3.jpg 4.jpg ruby crop.rb ../capybara-screenshot/shokai.png 7.73s user 1.82s system 89% cpu 10.663 total
7.73秒かかった。
ImageMagickはファイルにあわせて画像フォーマットを決めてくれるのに、mini_magickではformatメソッドで指定しないと元画像のままPNG形式で保存されてしまっていた。
exiftoolで確認すべき。
ImageMagick版
#!/usr/bin/env ruby img = ARGV.shift width, height = `identify '#{img}'`.split(/\s/).select{|i| i =~ /^\d+x\d+$/ }.first.split('x').map{|i| i.to_i} puts "#{width}x#{height}" w = width h = (w*1.41).to_i 0.upto(height/h) do |i| puts fname = "#{i}.jpg" puts cmd = "convert -quality 95 -crop #{w}x#{h}+0+#{h*i} #{img} #{fname}" system cmd end
結果
0.jpg convert -crop 1236x1742+0+0 ../capybara-screenshot/shokai.png 0.jpg 1.jpg convert -crop 1236x1742+0+1742 ../capybara-screenshot/shokai.png 1.jpg 2.jpg convert -crop 1236x1742+0+3484 ../capybara-screenshot/shokai.png 2.jpg 3.jpg convert -crop 1236x1742+0+5226 ../capybara-screenshot/shokai.png 3.jpg 4.jpg convert -crop 1236x1742+0+6968 ../capybara-screenshot/shokai.png 4.jpg ruby crop_imagemagick.rb ../capybara-screenshot/shokai.png 1.97s user 0.52s system 74% cpu 3.089 total
1.97秒だった。
ImageMagickを直に使ったほうが圧倒的に速い。
感想
- ImageMagickを直に使ったほうが速い。しかし・・
- 画像のサイズやフォーマットなどを読み取る場合、identifyコマンドを使うのだが文字列で返ってくるのでparseが面倒。mini_magickやrmagickを使ったほうが楽。
- 画像のサイズを変えたり、色調を補正するぐらいならImageMagickをそのまま使ったほうが楽だし、高速。
- 特に細かいオプションを設定したりする場合、それをラッパーから指定する方法を調べるのがめんどい。
- 複数の画像を重ねあわせたりするならmini_magickなどを使ったほうが書きやすい。
使い分け
ちょっと画像を加工→ImageMagickを直に使う
画像のプロパティを読み取り、細かくに加工(というか装飾)→mini_magick
がいいのでは。
画像をpdfファイルにまとめる
今までhomebrewで入れれるpdfjamを使っていたのだが、macportsにしかないpdflatexに依存しているのであまり使いたくない。
prawn(https://github.com/prawnpdf/prawn)を使うとRubyだけで作れるので、乗り換えることにした。
prawnはpngを入れると遅くなるので、jpegを使ったほうがいい。
gem install prawn
join-images.rb
#!/usr/bin/env ruby require 'rubygems' require 'prawn' puts out_fname = ARGV.pop p imgs = ARGV Prawn::Document.generate(out_fname) do imgs.each do |img| image(img, :fit => [bounds.absolute_right - bounds.absolute_left, bounds.absolute_top - bounds.absolute_bottom] ) start_new_page end end
結合する
ruby join-images.rb *.jpg out.pdf
フチ無し、画像をページぴったりにする
join-images-fit.rb
#!/usr/bin/env ruby require 'rubygems' require 'prawn' puts out_fname = ARGV.pop p imgs = ARGV Prawn::Document.generate(out_fname) do imgs.each do |img| image img, :at => [-1*bounds.absolute_left, bounds.absolute_top], :fit => [bounds.absolute_right+bounds.absolute_left, bounds.absolute_top+bounds.absolute_bottom] start_new_page end end
capybara-webkitでwebページのスクリーンショットを撮る
capybara使うと簡単にキャプチャできる。もともとjsのheadless testの為のツールなのでjsも実行されるし良い。
Macの場合
brew install qt gem install capybara capybara-webkit
#!/usr/bin/env ruby require 'rubygems' require 'capybara-webkit' driver = Capybara::Driver::Webkit.new 'web_capture' driver.visit 'http://shokai.org/blog/' driver.render 'out.png'
MacにGUIでログインしていなくてもキャプチャできる。モニタほぼ使ってないサーバー状態のMacで使いたかったのでありがたい。
webkit2png(http://d.hatena.ne.jp/shokai/20120214/1329201906)だとGUIでログインしないとwindowが見つからないというエラーでキャプチャできなかったが、capybara-webkitならxvfbも必要ない。
Ubuntuの場合
sudo apt-get install qt4-dev-tools xvfb gem install capybara capybara-webkit headless
GUIが入っていなくてもheadlessでxvfbを作れば良い。
#!/usr/bin/env ruby require 'rubygems' require 'capybara-webkit' require 'headless' Headless.ly do driver = Capybara::Driver::Webkit.new 'web_capture' driver.visit 'http://shokai.org/blog/' driver.render 'out.png' end
フォントが入っていないからか、日本語が表示できない
フォントを入れたら日本語でた!! id:myatsmoto に教えてもらった。
sudo apt-get install x-ttcidfont-conf ttf-kochi-mincho-naga10 ttf-kochi-gothic-naga10
画像のサイズを求める方法
ImageMagick
imagemagickについてくるidentifyコマンドを使う
identify ファイル名
結果
ファイル名 PNG 1200x4702 1200x4702+0+0 8-bit DirectClass 890KB 0.000u 0:00.000
mini_magick
ImageMagickのRubyラッパー。
gem install mini_magick
#!/usr/bin/env ruby require 'rubygems' require 'mini_magick' ARGV.each do |arg| puts arg img = MiniMagick::Image.open(arg) puts "#{img[:width]}x#{img[:height]}" end