ActiveSupportのRange拡張

active_support/core_ext/range/ 以下をざっとみてみた。

include_with_range.rb

Range#include_with_range?(val)はvalがRangeじゃなかったら単純にincludeしてるかを
判断し、Rangeだった場合はレシーバの範囲内に収まっているかどうかを検証する。

irb(main):005:0> require "active_support/core_ext/range"
=> []
irb(main):007:0> (1..10).include_with_range?(3)
=> true
irb(main):008:0> (1..10).include_with_range?(11)
=> false
irb(main):009:0> (1..10).include_with_range?(2..9)
=> true
irb(main):010:0> (1..10).include_with_range?(2..11)
=> false
irb(main):011:0> (1..10).include_with_range?(0..11)
=> false
overlaps.rb

Range#overlaps?(val)はvalがレシーブの一部にでも含まれているかどうかを検証する。

irb(main):015:0> (1..10).overlaps?(9..11)
=> true
irb(main):016:0> (1..10).overlaps?(2..10)
=> true
irb(main):017:0> (1..10).overlaps?(11..12)
=> false
conversions.rb

これはどの拡張クラスにもつくみたい。
Range#to_formatted_s(format=:default)はformat=:defaultでRangeのto_sをそのまま呼ぶ。
format=:dbを指定した場合Procが呼ばれてDBに問い合わせる文字列が帰る。

irb(main):004:0> (1..10).to_formatted_s
=> "1..10"
irb(main):003:0> require "active_support/time"
=> true
irb(main):004:0> date_range = Date.new(2012,8,16)..Date.new(2012,8,20)
=> Thu, 16 Aug 2012..Mon, 20 Aug 2012
irb(main):009:0> date_range.to_s(:db)
=> "BETWEEN '2012-08-16' AND '2012-08-20'"
irb(main):010:0> date_range.to_formatted_s(:db)
=> "BETWEEN '2012-08-16' AND '2012-08-20'"

ActiveSupportのArray拡張

active_support/core_ext/array/ 以下をざっとみてみた。

prepend_and_append.rb

<< -> appendに unshift -> prependにalias張る。

access.rb

要素にアクセスしやすいヘルパーみたいなもの。
Array#forty_two っていつ使うんだろ・・・

irb(main):012:0> require "active_support/core_ext/array/access"
=> false
irb(main):013:0> pochi = %w(p o c h i)
=> ["p", "o", "c", "h", "i"]
irb(main):014:0> pochi.from(2)
=> ["c", "h", "i"]
irb(main):015:0> pochi.to(2)
=> ["p", "o", "c"]
irb(main):017:0> %w(second third fourth fifth forty_two).each {|m| puts pochi.__send__(m) }
o
c
h
i

=> ["second", "third", "fourth", "fifth", "forty_two"]
irb(main):018:0> 
uniq_by.rb

Deprecation出てる。Array#uniq読んでるだけ。

wrap.rb

何でもArrayっぽくしてくれる。

irb(main):020:0* require "active_support/core_ext/array/wrap"
=> true
irb(main):021:0> Array.wrap(nil)
=> []
irb(main):022:0> Array.wrap("pochi")
=> ["pochi"]
irb(main):023:0> Hoge = Class.new()
=> Hoge
irb(main):024:0> Array.wrap(Hoge)
=> [Hoge]
irb(main):025:0> 
extract_options.rb

よくRailsだと引数の最後はHashにすることがあるのでそれだけ取り出す
Array#extract_options!で取り出すことができる。
さりげなくHashに自分がHashインスタンスか確認するextractable_options?が定義されてる。

irb(main):025:0> require "active_support/core_ext/array/extract_options"
=> true
irb(main):026:0> array = ["pochi", "kyoto", age: 11]
=> ["pochi", "kyoto", {:age=>11}]
irb(main):027:0> array.extract_options!
=> {:age=>11}
irb(main):028:0> array = ["pochi", "kyoto"]
=> ["pochi", "kyoto"]
irb(main):029:0> array.extract_options!
=> {}
irb(main):030:0> 
grouping.rb

Array#in_groups_of(number, fill_with=nil)はfill_withがfalseならeach_sliceを呼ぶだけで
fill_withがある場合は必要個数分concatしてからeach_sliceを呼ぶ。
当然blockにも対応

irb(main):033:0> require "active_support/core_ext/array/grouping"
=> true
irb(main):035:0> (1..10).to_a.in_groups_of(3, "pochi")
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, "pochi", "pochi"]]
irb(main):036:0> (1..10).to_a.in_groups_of(3)
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, nil, nil]]
irb(main):037:0> (1..10).to_a.in_groups_of(3, false)
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
irb(main):038:0> (1..10).to_a.in_groups_of(3, 4) { |g| puts g.max }
3
6
9
10
=> nil
irb(main):039:0> 

Array#in_groups(number, fill_with=nil)はArray#in_groups_ofに似てるけど
fillする挙動が違う。

irb(main):040:0> (1..10).to_a.in_groups(3, "pochi")
=> [[1, 2, 3, 4], [5, 6, 7, "pochi"], [8, 9, 10, "pochi"]]
irb(main):041:0> (1..10).to_a.in_groups(3)
=> [[1, 2, 3, 4], [5, 6, 7, nil], [8, 9, 10, nil]]
irb(main):042:0> (1..10).to_a.in_groups(3, false)
=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
irb(main):043:0> (1..10).to_a.in_groups(3, 4) { |g| puts g.max }
4
7
10
=> [[1, 2, 3, 4], [5, 6, 7, 4], [8, 9, 10, 4]]
irb(main):044:0> 

Array#split(value=nil, &block)ということで条件をみてArrayを配置してくれる。
splitのコードはtapのほうが好きだけどblockの使い方は勉強になる。

irb(main):044:0> ["hoge", "moge", "fuga"].split("moge")
=> [["hoge"], ["fuga"]]
irb(main):045:0> ["hoge", "moge", "fuga"].split {|message| message == "moge" }
=> [["hoge"], ["fuga"]]
irb(main):046:0> 
conversions.rb

Array#to_sentence(options={})はそれっぽい文字列に変換してくれる。
localeをオプションに連結文字を変更できる。

irb(main):047:0> require "active_support/core_ext/array/conversions"
=> true
irb(main):048:0> ["pochi", "miitan", "mineko"].to_sentence
=> "pochi, miitan, and mineko"
irb(main):050:0> ["pochi", "miitan", "mineko"].to_sentence(words_connector: ' and ', two_words_connector: ' too ', last_word_connector: ' after all ')
=> "pochi and miitan after all mineko"
irb(main):051:0> [].to_sentence
=> ""
irb(main):052:0> ["pochi", "miitan"].to_sentence
=> "pochi and miitan"
irb(main):053:0> 

Array#to_formatted_s(format = :default)はオブジェクトが詰まってる配列を
to_sを読んで文字列にしてくれる。
DBを渡してあげるとid返してくれたりする。

irb(main):059:0> class Person; attr_accessor :name; def to_s; name; end; end
=> nil
irb(main):060:0> pochi = Person.new
=> 
irb(main):061:0> pochi.name = "pochi"
=> "pochi"
irb(main):062:0> miitan = Person.new
=> 
irb(main):063:0> miitan.name = "miitan"
=> "miitan"
irb(main):064:0> [pochi, miitan].to_formatted_s
=> "[pochi, miitan]"
irb(main):065:0> class Person; attr_accessor :id; end
=> nil
irb(main):066:0> pochi.id = 3
=> 3
irb(main):067:0> miitan.id = 2
=> 2
irb(main):068:0> [pochi, miitan].to_formatted_s(:db)
=> "3,2"
irb(main):069:0> 

Array#to_xml(options={})は配列からxmlを生成してくれる。
ActiveSupport::XmlMiniってのを使ってるみたい。

irb(main):070:0> [pochi, miitan].to_xml
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<people type=\"array\">\n  <person type=\"Person\">pochi</person>\n  <person type=\"Person\">miitan</person>\n</people>\n"
irb(main):071:0> 

MySQLの対応方法

[rails] uninitialized constant MysqlCompat::MysqlResの対処法

rails2.3.9とかでアプリを動かそうとすると上記のエラーが出てはまったのでメモ。
周りの人たちはだいたいmac 64bit化したことで起きてたようですが、
当方32bit redhat + ruby 1.8.7とかで発生しました。(mysqlライブラリのバージョンは2.8)

gem install -v 2.7 mysql

とりあえずこれで動くようになりました。
おやすみなさい。

Notificationsの使い方

FirefoxでNotification を利用できるようになり、(Chromeはデフォルトで実装されてる)今後実装する機会も多くなりそうです。
Google先生に聞いてみるとdesktopifyが有名ですが中身を見ると自分で実装した方が早い気がしてます。
簡単に以下使い方をメモで残しておきます。

今回確認する用のアプリ

今回はRails 3.1.0rc1で簡単なアプリを作ってみました。

f:id:POCHI_BLACK:20110527181852p:image

簡単ですが、以下の流れで確認していきます。

  • クライアントにデスクトップ通知の確認を実施
  • 現状の通知状態を確認
  • 実際に通知してみる

クライアントにデスクトップ通知の確認を実施

画面のActivateを選択すると以下のダイアログができてデスクトップ通知を有効にするかどうか確認します。

f:id:POCHI_BLACK:20110527182309p:image

ここのコードはこんな感じです。(CoffeeScriptです)

$(document).ready ->
  $("#activate").live("click", ->
    window.webkitNotifications.requestPermission()
  )

<button id="activate">Activate</button>

上記のwindow.webkitNotifications.requestPermission()を呼べばユーザさんに確認できます。

現状の通知状態を確認

画面のConfirmを選択すると以下のダイアログができてデスクトップ通知を有効にするかどうか確認します。

f:id:POCHI_BLACK:20110527182947p:image

ここのコードはこんな感じです。(CoffeeScriptです)

$(document).ready ->
  $("#confirm").live("click", ->
    alert(window.webkitNotifications.checkPermission())
  )

<button id="confirm">Confirm</button>

0がユーザに許可されている状態、2がユーザが拒否している状態です。

実際に通知してみる

画面のNotification!を選択すると実際に通知が表示されます。

f:id:POCHI_BLACK:20110527182948p:image

ここのコードはこんな感じです。(CoffeeScriptです)

$(document).ready ->
  $("#notification").live("click", ->
    window.webkitNotifications.createNotification("mail.png", "pochi", "bowbow!").show()
  )

<button id="notification">Notification!</button>

showメソッドで表示することができます。

まとめ

jQueryPlugin使うのもいいですが結構簡単に使えるのでそのまま呼び出してもいいかなと個人的に思ってます。以下はなんか注意。。。

  • MacユーザはGrowl動いてないとだめ
  • FireFoxだとアドオンだからHTML読み込んだあとでもwebkitNotificationが初期化されてない(僕の勉強不足)
  • FireFoxだけどff5-notifications使ってるときはwebkitNotification使う(mozNotificationか迷った・・・)

作ったコード

Thorで書いたタスクのテストをする方法

Thorでタスクを書くとそのメソッドが普通のRubyのようには呼べません。
それでもやっぱりテストは書きたいのでThorのspecをいろいろ見てたらありました。

# encoding: utf-8
require "rubygems"
require "thor"
require "rspec"
require "stringio"

class Sample < Thor
  desc "name", "sample name"
  def name
    puts "pochi"
  end
end

describe Sample do
  it "should display 'pochi'" do
    capture(:stdout) {
      Sample.new.invoke("name")
    }.strip.should == "pochi"
  end
end