rubyで文字列内の式展開で#{@hoge}の{}は省略できる

ruby style guideというのが話題になっていて,
参考になるところもあり,否定したくなるところもあり
で楽しく読んでいたら知らない文法に出くわしてビビったので.
https://github.com/bbatsov/ruby-style-guide

class Person
  attr_reader :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  # bad
  def to_s
    "#{@first_name} #{@last_name}"
  end

  # good
  def to_s
    "#@first_name #@last_name"
  end
end

( ゚д゚)

こんなんあったんかい

ためしてみた

# できるし!
pry(main)> @a = 1
=> 1
pry(main)> puts "#@a"
1

# 変数名に使われない記号
# が出てくると区切られるぽい
pry(main)> puts "#@a hello"
1 hello
pry(main)> puts "#@a$hello"
1$hello
pry(main)> puts "#@a-hello"
1-hello

# インスタンス変数以外もいけるか

# グローバル変数 => ok
pry(main)> $a = 1
=> 1
pry(main)> puts "#$a hello"
1 hello

# クラス変数 => ok
pry(main)> @@a = 1
=> 1
pry(main)> puts "#@@a hello"
1 hello

# 普通の変数 => ng
pry(main)> a = 1
=> 1
pry(main)> puts "#a hello"
#a hello

# 記号っぽい文字からはじめれば…
# => やっぱだめか
pry(main)> _a = 1
=> 1
pry(main)> puts "#_a hello"
#_a hello

覚えとこう

LingrからRSS生成するサービスつくった

最近(だいぶまえから?)Lingrがアツい!!


でも未読管理ができなかったり,
開きっぱなしにしておくのがだるかったりするので
発言をRSSに変換するサービスをつくりました.


使い方

  1. http://lingr.com/bot/lingr2rss このURLにアクセス
  2. Botをチャットに追加する(要チャットルームのオーナー権限)

かんたんですね!


登録したらあとは
http://lingr2rss.yayugu.net/
でみれます.


たとえばこんな感じになる
http://lingr2rss.yayugu.net/lokka_ja


割と便利だと思うので使ってみてください!


ソースコード
https://github.com/yayugu/lingr2rss

DataMapperでdefault_scope的なことをする

LokkaがDataMapperなのでしかたなく使ってるわけですが,正直DMはあんまりいいライブラリではありません.
ActiveRecordと迷っているなら間違いなくActiveRecordを使うべきです.

で,DataMapperにはActiveRecordでのdefault_scopeにあたるものがありません.
正確にはdefault_scopeというメソッドはありますがprivate APIですし,あなたの期待する動作はしないでしょう.

default_orderを使う

default_scopeで設定したかったものがorderの場合はdefault_orderで代替できます.

class MyModel
  include DataMapper::Resource

  default_order 'created_at DESC'
end
||<</del>

追記:ダメっぽい. default_scopeは他の用途で使うらしいので
↓の方法でやりましょう.orderだけならgetのことは関係ないので安心

**firstとallを上書きする
強引な方法としてfirstとallを上書きしてしまう手があります.
例えば :draft => false というscopeを付加したい場合,以下の様にします.

>|ruby|
  class << self
    def _default_scope
      {:draft => false}
    end

    def first_with_scope(limit, query = DataMapper::Undefined)
      unless limit.kind_of? Integer
        query = limit
        limit = 1
      end
      query = _default_scope.update(query) if query.kind_of? Hash
      query = _default_scope if query == DataMapper::Undefined
      first_without_scope query
    end
    alias_method_chain :first, :scope

    def all_with_scope(query = DataMapper::Undefined)
      query = _default_scope.update(query) if query.kind_of? Hash
      query = _default_scope if query == DataMapper::Undefined
      all_without_scope query
    end
    alias_method_chain :all, :scope
  end

  def self.unscoped
    klass = self.clone
    class << klass
      alias_method :first, :first_without_scope
      alias_method :all, :all_without_scope
    end
    klass
  end

問題点

この方法ではgetではscopeが作用しません.
getにscopeを付加するにはfirstに変換して考える必要がありますが
PrimaryKeyのcolumn名がわからないと変換できないからです.

sqliteの違う環境で動作させたときだけ発生する怖いバグ

Time Zone の異なる場所で記録したDateTimeのデータでソートしようとするとソート順が正しくなりません.

例.

sqlite> select id, created_at from entries;
1|2011-01-09T05:39:08+09:00
2|2011-01-09T05:39:08+09:00
3|2011-01-08T15:40:08-05:00
sqlite> select id, created_at from entries order by created_at desc;
1|2011-01-09T05:39:08+09:00
2|2011-01-09T05:39:08+09:00
3|2011-01-08T15:40:08-05:00

2011-01-08T15:40:08-05:00は
2011-01-09T05:39:08+09:00より1分あとのははずですが.ソート結果は逆になっています.

原因

sqliteにはそもそもDate型とかDateTime型といったものがありません.
created_atはただの文字列として定義されてるのでソート結果も頭の文字から
並べ換えていくだけなわけで,Time Zoneは正しく処理できません.

解決法

  • 異なるTimeZoneの時間を含めない
  • アプリケーション側で取得したあとでソートするようにする

DotCloudにSinatraアプリ(Lokka)を設置してみた

最近Lokkaにはまってる


で,せっかくなのでいろんな環境でデプロイしてみたりしてるんだけど,
その中でもDotCloudでのデプロイは面倒という話

DotCloudとは

PaaSとか言われるものに分類されるっぽい
HerokuとかGAEとかと一緒にされますが,
それらよりもいろいろな言語とかデータベースとか
その他ソフトウェアに対応してる

DotCloudめんどう

DotCloudはいろいろな部分が低レベル
もともとruby専用だったHerokuと違い
使う言語やDBを指定しないと行けなかったり,
設定がruby環境変数ではなくファイルで置かれていたり,
sshで作業することが前提となっていたり(そのおかげでcronとか普通に使えるのは便利)


どちらかというとレンタルサーバで作業している気分になれる

仕様変更

ついこの間バージョンアップがあったようで使い方が変更されている
公式ドキュメント以外ほぼ情報がないところが多くて大変困る

Lokkaのデプロイ

めんどくさかったので一番楽そうな方法をまとめた

ダウンロード
git clone git://github.com/yayugu/lokka.git
git checkout dotcloud

あるいは
公式のLokkaをcloneして

diff --git a/config.yml b/config.yml
index 0dab043..98de2a4 100644
--- a/config.yml
+++ b/config.yml
@@ -1,5 +1,15 @@
+<% 
+# for dotcloud
+dotcloud = 
+  if File.exist? '/home/dotcloud/environment.json'
+    JSON.parse(File.read('/home/dotcloud/environment.json'))['DOTCLOUD_DATA_SQL_URL'].gsub('pgsql', 'postgres') + '/template1'
+  else 
+    nil
+  end
+%>
+
 production:
-  dsn: <%= ENV['DATABASE_URL'] || ENV['DUOSTACK_DB_MYSQL'] %>
+  dsn: <%= ENV['DATABASE_URL'] || ENV['DUOSTACK_DB_MYSQL'] || dotcloud %>
 development:
   dsn: sqlite3://<%= root %>/db/development.sqlite3
 test:
diff --git a/dotcloud.yml b/dotcloud.yml
new file mode 100644
index 0000000..3607612
--- /dev/null
+++ b/dotcloud.yml
@@ -0,0 +1,7 @@
+www:
+  type: ruby
+  exclude_bundler_groups:
+    - development
+    - test
+data:
+  type: postgresql

dotcloudではdbのURLとかはruby環境変数に入れてくれないので読みにいく必要がある.


それからpostgresなのはmysqlだとデフォルトデータベースがないので,dbのサーバにsshでログインして'create database lokka;'とかやる必要があるから.
postgresだとなぜかtemplate1という空のデータベースが1つつくられてあるのでそれを利用*1



デプロイ

dotcloudの各種設定をしてから

dotcloud create lokka
dotcloud push -bdotcloud lokka
dotcloud run lokka.www "cd current && rake db:setup"

dotcloudブランチをプッシュする*2


dotcloud runはsshでログインして1行実行するコマンド.wwwはrubyとかがおいてあるサーバ.dataだとmysqlのサーバになる.で,なぜかログインしたディレクトリ直下ではなく./currentにpushしたデータがあるのでcdしてrake

おしまい

自由度が高い&変な抽象化っていうのは厄介だね.
でも無料でいろいろできるしパフォーマンスもHerokuと比べて良かった気がしたので
そのへんはいいところ

特にHerokuの泣きどころの久しぶりのアクセス1回目はすごく遅いってもんだいがあんまりなさそう(な気がした)のはいいね

*1:Herokuだと基本はsharedな中にそのアプリ用のデータベースが自動でつくられる

*2:ちなみに'dotcloud push'はデフォルトではrsyncでgitかmercurialを使ってればそれでプッシュするという混乱極まりない仕様になっている

Twitterの(公式よりまともな)RSSを生成するサービス Twitter Good RSS をつくったよ!

改良版のTwitter Great RSSをつくりました。今後はこちらをお使いください









つくりました! こんな感じ↓にTwitter公式のアレなRSSと違いまともなRSSを生成します。



URL、#ハッシュタグ、@リプライに対応。さらに公式の画像サービスpic.twitter.comの画像をインライン展開できます。


さらに、リストからRSSを生成する機能もつけました。
なぜか公式ではRSSないみたいなので便利なのではないでしょうか。


URLはこちら↓

http://twittergoodrss.herokuapp.com/


こんな人に便利!?

  • ツイートを未読管理したい
  • 一人一人のtweetを混ぜずに集中的によみたい
  • リスト分けしてるけど全部巡回するのだるくなってきた
  • リストに人入れすぎて全部読んでないのにTwitterの制限で最後まで辿れなくなってる*1
  • Twitter公式のRSSまじうんこ。アイコンないと誰のツイートかピンと来ない。URLとかハッシュタグにリンクぐらいつけろよ!

というわけで

TwitterGoodRSSで快適なRSSライフを!
http://twittergoodrss.herokuapp.com/


ソースコード

https://github.com/yayugu/twitterGoodRSS
気軽にpull requestとかissueとかお待ちしています。
herokuに簡単にデプロイできるようになってます。



2013/03/05 追記:
Twitter API 1.1に対応しました

*1:リストは普通のタイムラインよりさかのぼれる制限が厳しい…気がする