Created
December 2, 2012 15:38
-
-
Save flada-auxv/4189358 to your computer and use it in GitHub Desktop.
モンキーパッチの影響と対応策。ActiveSupportに見られるモジュールを利用する手法とRuby2.0から導入されるrefinments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# モンキーパッチには二つの問題がある。 | |
# ・変更の範囲が「グローバル」である事。 | |
# ・変更が行われた事が「見えづらい」事。 | |
# | |
# 変更が見えづらい点への対応策として、ActiveSupportではモジュールを利用してモンキーパッチを明示的にしている。 | |
# rails/activesupport/lib/active_support/core_ext配下。 | |
# モジュールにメソッドを定義して、オープンクラスでインクルードする事で、#ancestors()などで確認する事が出来る。 | |
# もちろんこれだけでは、「グローバル」な変更への配慮は出来ていないが。 | |
module MyApp | |
module CoreExtensions | |
module Fixnum | |
module TimeFormat | |
UNIT_SCORES = { | |
h: 3600, | |
m: 60, | |
s: 1 | |
} | |
# @param format Time#strftimeの引数と同じ 日付に対する指定はしない事 | |
# @param unit :h = 時間、:m = 分間、:s = 秒間 | |
# 86400秒以上の数値に対して呼び出された場合はnilを返す | |
def to_time(format: "%H:%M", unit: :m) | |
second_notation = self * UNIT_SCORES[unit] | |
return nil if second_notation > 86400 | |
h, m, s = 0, 0, 0 | |
m, s = second_notation.divmod(60) | |
h, m = m.divmod(60) if m > 60 | |
Time.now.instance_eval do | |
return Time.local(year, mon, day, h, m, s).strftime(format) | |
end | |
end | |
end | |
end | |
end | |
end | |
class Fixnum | |
include MyApp::CoreExtensions::Fixnum::TimeFormat | |
end | |
p 480.to_time # => "08:00" | |
p 14.to_time(unit: :h) # => "14:00" | |
p Fixnum.ancestors | |
# => [Fixnum, | |
# MyApp::CoreExtensions::Fixnum::TimeFormat, | |
# Integer, | |
# Numeric, | |
# Comparable, | |
# Object, | |
# PP::ObjectMixin, | |
# Kernel, | |
# BasicObject] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# refinementsを使えば、影響をmoduleやclass単位に限定する事が出来るので「グローバル」なスコープを汚染しない。 | |
# 影響を与えるそのスコープにてusing句で明示されるので、「見えづらい」点も解消するはず。 | |
# もともと「見えづらい」というは、グローバルな影響を及ぼす事に起因してる面もあると思う。 | |
module TimeFormatExtensions | |
refine Fixnum do | |
UNIT_SCORES = { | |
h: 3600, | |
m: 60, | |
s: 1 | |
} | |
# @param format Time#strftimeの引数と同じ 日付に対する指定はしない事 | |
# @param unit :h = 時間、:m = 分間、:s = 秒間 | |
# 86400秒以上の数値に対して呼び出された場合はnilを返す | |
def to_time(format: "%H:%M", unit: :m) | |
second_notation = self * UNIT_SCORES[unit] | |
return nil if second_notation > 86400 | |
h, m, s = 0, 0, 0 | |
m, s = second_notation.divmod(60) | |
h, m = m.divmod(60) if m > 60 | |
Time.now.instance_eval do | |
return Time.local(year, mon, day, h, m, s).strftime(format) | |
end | |
end | |
end | |
end | |
module MyApp | |
using TimeFormatExtensions | |
p 480.to_time # => "08:00" | |
p 14.to_time(unit: :h) # => "14:00" | |
end | |
p 480.to_time # => NoMethodError |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment