ruby – bluegold https://blog.bluegold.me OpenSolaris と MacBook で自宅ネットワークを構築するメモ Mon, 23 Aug 2010 18:32:38 +0000 ja hourly 1 https://wordpress.org/?v=5.2.1 6047458 Rails 2.3 のタイムゾーン https://blog.bluegold.me/2009/09/rails-2-3-active_record-timezone/ https://blog.bluegold.me/2009/09/rails-2-3-active_record-timezone/#respond Mon, 14 Sep 2009 11:08:34 +0000 http://blog.bluegold.me/?p=278 2006年頃に Rails 1.2 で作成したアプリケーションを Rails 2.3 にアップグレードしています。

プログラムの移行自体は1週間ほどで完了したのですが、テストをしていてタイムゾーン関連の問題に遭遇しました。

データベースに有効期限を表すフィールドがあるのですが、1時間前から1時間後まで有効なレコードを作成して、現在が有効期間内かどうかを調べるテストが失敗したので問題に気がつきました。

Rails 2.x ではタイムゾーンが導入されたのは知っていたので、下のように設定を行っていました。

config.time_zone = 'Tokyo'
config.active_record.default_timezone = 'Tokyo'

しかし、ログを見ていると JST と UTC とタイムゾーンが混ざっているようだったので、単純なアプリを作成して調べてみました。すると、以下のような結果に

c = Sample.find(:first)
>> c[:created_at]
=> Mon, 24 Aug 2009 17:09:49 +0000
>> c.created_at
=> Tue, 25 Aug 2009 02:09:49 JST +09:00
>> c[:created_at].class
=> DateTime
>> c.created_at.class
=> ActiveSupport::TimeWithZone

同じフィールドでも [] メソッドでデータを取得するのと、フィールド名を指定して取得するので、クラスもタイムゾーンも異なるんですね。ちょっとビックリしました。

どこかにタイムゾーンを意識しないコードがあって、この2つを混同してしまってるんだろうな。
調べるのはメンドクサイな。

]]>
https://blog.bluegold.me/2009/09/rails-2-3-active_record-timezone/feed/ 0 278
Rails 1.2.6 と gem 1.3.0 を一緒に使う https://blog.bluegold.me/2008/12/rails-126-and-gem-130/ https://blog.bluegold.me/2008/12/rails-126-and-gem-130/#respond Wed, 17 Dec 2008 16:18:53 +0000 http://blog.bluegold.me/?p=132 Merbが最近はやっているようなので、インストールして使ってみようと思いました。Merb には Rubygems 1.3.0 以上が必要なのでアップデートしたところ、仕事で開発している Rails 1.2.6 で作られたアプリケーションに gem の deprecated メッセージが出てくるようになってしまいました。

たとえば script/console を実行すると以下のようなメッセージが出てきます。

$ script/console 
Gem::SourceIndex#search support for String patterns is deprecated
./script/../config/boot.rb:20 is outdated
Loading development environment.
Gem::SourceIndex#search support for String patterns is deprecated
./script/../config/../config/boot.rb:20 is outdated
>> 

このアプリは Rails を使っているのでとうぜんWeb用のアプリなのですが、管理用に独自のコマンドラインシェルを用意しています。こちらのコマンドの実行時にも同様のメッセージが出てきてしまっています。「Rails 2.2 系に上げるいい時期かな」とも思わないでもないのですが、製品として提供している物なので、今期末にいくつか控えている納品を終えるまではバージョンを上げるわけにもいきません。

仕方がないのでクイックハック
script/console の最初で stderr を /dev/null に捨てるようにしました。

#!/usr/bin/env ruby
$stderr.reopen('/dev/null')
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/console'

deprecated なメッセージを簡単に抑制する設定とかもあるんだろうか。。。

]]>
https://blog.bluegold.me/2008/12/rails-126-and-gem-130/feed/ 0 132
last.fm のプレイリストをブログに表示するには https://blog.bluegold.me/2008/12/lastfm-playlist/ https://blog.bluegold.me/2008/12/lastfm-playlist/#respond Thu, 11 Dec 2008 15:53:57 +0000 http://blog.bluegold.me/?p=117 last.fm

HiGash.Netの中の人にWordPressのキレイなテーマを作ってもらったので、last.fmの「最近聴いたトラック」を表示するプログラムを作りました。

last.fm の公式のウィジェットを使用すれば簡単にブログに貼付ける事ができますが、公式の物はFlashを使っていて自分でデザインを変更できないので、自分で作ってみました。last.fmはaudioscrobblerというAPIを用意しているので、このAPI経由で情報を取得します。今回は Ruby の scrobbler gemを利用しています。

scrobbler gem のインストールは以下のように簡単です。

$ sudo gem install scrobbler

scrobblerのドキュメントを見ながら、プログラムを書いていきます。
手順はだいたい次のようになります。

  1. last.fmのユーザの「最近聴いたトラック」の一覧を取得する
  2. トラックのアルバムアートワークを取得する

last.fmのユーザの「最近聴いたトラック」の一覧を取得する

scrobblerライブラリを使うと簡単で、last.fmのユーザ名を指定してScrobbler::Userのオブジェクトを作成するだけです。

user = Scrobbler::User.new('bluegold')
recent_tracks = user.recent_tracks

Scrobbler::User#recent_tracks の戻り値はScrobbler::TrackのArrayになっています。Scrobbler::Track は再生した曲の情報を表すオブジェクトで、曲のアルバム名やアーチスト名、last.fmのURLなどの情報を保持しています。last.fmの URLは、たとえば Sheryl Crow の Real Goneの場合はこのページの事です。

最近再生したトラックを表示するだけなら、ここまでで終わりです。

トラックのアルバムアートワークを取得する

Scrobbler::Track のオブジェクトにもimageやthumbnailなどのattributeは存在するのですが、これらは’only seems to be used on top tracks for tag’とのことでScrobbler::User#recent_tracksでは値が設定されていません。そこでトラックのアーチスト名とアルバム名からScrobbler::Albumのオブジェクトを作成して、そこからアルバムアートワークを取得します。Scrobbler#Trackのオブジェクトから得られるアルバム名は(アーチスト名も?)エスケープされていて、そのままでは正しくデータを取得出来ない場合があったので、CGI#unescapeHTML を利用して元に戻しています。

track = recent_tracks.first
album = Scrobbler::Album.new(
  track.artist,
  CGI.unescapeHTML(track.albumname)
)
image_url = album.image(:small)

上のコードで1曲分のアートワーク画像へのURLが得られるので、表示したい曲数分繰り返します。

あとは好きなようにHTMLを書いてスタイルを設定するだけです。完成した結果はこのブログのフッターに表示されている通りです。

]]>
https://blog.bluegold.me/2008/12/lastfm-playlist/feed/ 0 117
WordPressのバックアップを Gmail に保存する その3 https://blog.bluegold.me/2008/10/backup-wordpress-to-gmail-3/ https://blog.bluegold.me/2008/10/backup-wordpress-to-gmail-3/#respond Mon, 20 Oct 2008 16:28:18 +0000 http://blog.bluegold.me/?p=45 前回、暗号化を行った事によりバックアップの保存の目的はほぼ果たしているのですが、気持ちが悪いので添付ファイルについても考えてみました。

gmail と uuencode をキーワードに Google で検索した所、mutt を使うのが一般的らしい。
↓のように ‘-a’ キーワードで添付するファイルを指定するだけで添付ファイルとして扱ってくれます。

mutt -a name.afz -a mysql_name.afz -s "name backup `date`" to_address

複数の添付ファイルにも対応しているので、この方法で問題ないかとも思ったのですが、1つだけ問題がありました。mutt では Envelope From を引数で変更することが出来ず、muttrc/.muttrc に別途設定する必要があります。

なんかめんどくさそうな感じがしたので、結局は Ruby でフィルタプログラムを書くことにしました。

以下のような物になりました。

#!/usr/bin/env ruby
#
# sendmail.rb</p>

require 'rubygems'
require 'tmail'
require 'net/smtp'
require 'nkf'
require 'etc'
require 'socket'
require 'optparse'


def usage( status, msg = nil )
  output = (status == 0 ? $stdout : $stderr)
  output.puts msg if msg
  output.print(&lt;&lt;EOS)
Usage: cat msg | #{File.basename $0} [-j|--ja] [-s <subject>] [-f <from>] <to>

  -s,--subject=sbj   subject of the message. (default=(none))
  -f,--from=from     from address.
  -a,--attachment=file attachment
  -j,--ja            handle japanese message. (default=off)

EOS
  exit status
end

def main(args)
  subject = nil
  from = guess_from_address()
  to = []
  attachments = []
  ja_locale = false

  OptionParser.new do |opt|
    opt.banner = "Usage: #{$0} [options]"

    opt.on('-s', '--subject=subj', 'subject of the message. (default=(none))') do |arg|
      subject = arg
    end
    opt.on('-f', '--from=from', 'from address.') do | arg|
      from = arg
    end
    opt.on('-j', '--ja', 'handle japanese message. (default=off)') do
      ja_locale = true
    end
    opt.on('-a', '--attachment=file', 'attachment') do |arg|
      attachments &lt;&lt; arg
    end

    to = opt.parse!(args)
  end

  usage(1) if to.empty?

  setup_mail(from, to, subject, $stdin.read, ja_locale, attachments)
end

def setup_mail( from, to, subject, body, ja_locale, attachments )
  mail = TMail::Mail.new
  mail.date = Time.now
  mail.from = from
  mail.to = to
  mail.subject = subject if subject
  mail.mime_version = '1.0'

  # 本文の処理
  if attachments.empty?
    message = mail
  else
    message = TMail::Mail.new
    message.transfer_encoding = '7bit'
  end
  if ja_locale
    message.body = <span class="caps">NKF.</span>nkf('-j', body)
    message.set_content_type 'text', 'plain', 'charset' =&gt; 'iso-2022-jp'
  else
    message.body = body
    message.set_content_type 'text', 'plain'
  end

  # 添付ファイルの処理
  unless attachments.empty?
    mail.parts.push(message)

    attachments.each do |filepath|
      body = nil
      File.open(filepath) { |f| body = f.read } rescue nil
      next if body.nil?

      attachment = TMail::Mail.new
      filename = File.basename(filepath)

      encoded_body = [body].pack('m').chomp.gsub(/.{76}/, "\\1\n")
      attachment = TMail::Mail.new
      attachment.body = encoded_body
      attachment.transfer_encoding = 'base64'
      attachment.set_content_type('application', 'octet-stream', 'name' =&gt; filename)
      attachment.set_content_disposition('attachment', 
                 'filename' =&gt; filename)

      mail.parts.push(attachment)
    end

    mail.write_back
  end

  puts mail.encoded

  mail
end

def guess_from_address
  user = getlogin()
  unless user
    $stderr.puts 'cannot get user account; abort.'
    exit 1
  end
  if domain = (Socket.gethostname || <span class="caps">ENV</span>['HOSTNAME'] || <span class="caps">ENV</span>['HOST'])
    user + '@' + domain
  else
    user
  end
end

def getlogint
  begin
    require 'etc'
    Etc.getlogin
  rescue LoadError
    <span class="caps">ENV</span>['LOGNAME'] || <span class="caps">ENV</span>['USER']
  end
end

main(ARGV)

TMail のサンプルの sendmail.rb をほぼそのまま使っています。
引数 ’-a’ で添付ファイルを指定出来るように変更しました。(getopts が deprecated になっていたので optparse で書き直しています。)

]]>
https://blog.bluegold.me/2008/10/backup-wordpress-to-gmail-3/feed/ 0 45