monetra-ruby 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +35 -0
- data/lib/monetra.rb +239 -0
- data/lib/monetra/active_support.rb +42 -0
- data/lib/monetra/active_support/binding_of_caller.rb +84 -0
- data/lib/monetra/active_support/breakpoint.rb +523 -0
- data/lib/monetra/active_support/caching_tools.rb +62 -0
- data/lib/monetra/active_support/clean_logger.rb +38 -0
- data/lib/monetra/active_support/core_ext.rb +1 -0
- data/lib/monetra/active_support/core_ext/array.rb +7 -0
- data/lib/monetra/active_support/core_ext/array/conversions.rb +72 -0
- data/lib/monetra/active_support/core_ext/array/grouping.rb +46 -0
- data/lib/monetra/active_support/core_ext/bigdecimal.rb +3 -0
- data/lib/monetra/active_support/core_ext/bigdecimal/formatting.rb +7 -0
- data/lib/monetra/active_support/core_ext/blank.rb +50 -0
- data/lib/monetra/active_support/core_ext/cgi.rb +5 -0
- data/lib/monetra/active_support/core_ext/cgi/escape_skipping_slashes.rb +14 -0
- data/lib/monetra/active_support/core_ext/class.rb +3 -0
- data/lib/monetra/active_support/core_ext/class/attribute_accessors.rb +44 -0
- data/lib/monetra/active_support/core_ext/class/inheritable_attributes.rb +115 -0
- data/lib/monetra/active_support/core_ext/class/removal.rb +24 -0
- data/lib/monetra/active_support/core_ext/date.rb +6 -0
- data/lib/monetra/active_support/core_ext/date/conversions.rb +39 -0
- data/lib/monetra/active_support/core_ext/enumerable.rb +62 -0
- data/lib/monetra/active_support/core_ext/exception.rb +33 -0
- data/lib/monetra/active_support/core_ext/hash.rb +13 -0
- data/lib/monetra/active_support/core_ext/hash/conversions.rb +148 -0
- data/lib/monetra/active_support/core_ext/hash/diff.rb +11 -0
- data/lib/monetra/active_support/core_ext/hash/indifferent_access.rb +88 -0
- data/lib/monetra/active_support/core_ext/hash/keys.rb +53 -0
- data/lib/monetra/active_support/core_ext/hash/reverse_merge.rb +25 -0
- data/lib/monetra/active_support/core_ext/integer.rb +7 -0
- data/lib/monetra/active_support/core_ext/integer/even_odd.rb +24 -0
- data/lib/monetra/active_support/core_ext/integer/inflections.rb +15 -0
- data/lib/monetra/active_support/core_ext/kernel.rb +4 -0
- data/lib/monetra/active_support/core_ext/kernel/agnostics.rb +11 -0
- data/lib/monetra/active_support/core_ext/kernel/daemonizing.rb +15 -0
- data/lib/monetra/active_support/core_ext/kernel/reporting.rb +51 -0
- data/lib/monetra/active_support/core_ext/kernel/requires.rb +24 -0
- data/lib/monetra/active_support/core_ext/load_error.rb +38 -0
- data/lib/monetra/active_support/core_ext/logger.rb +16 -0
- data/lib/monetra/active_support/core_ext/module.rb +7 -0
- data/lib/monetra/active_support/core_ext/module/aliasing.rb +57 -0
- data/lib/monetra/active_support/core_ext/module/attr_internal.rb +31 -0
- data/lib/monetra/active_support/core_ext/module/attribute_accessors.rb +44 -0
- data/lib/monetra/active_support/core_ext/module/delegation.rb +41 -0
- data/lib/monetra/active_support/core_ext/module/inclusion.rb +11 -0
- data/lib/monetra/active_support/core_ext/module/introspection.rb +21 -0
- data/lib/monetra/active_support/core_ext/module/loading.rb +13 -0
- data/lib/monetra/active_support/core_ext/name_error.rb +20 -0
- data/lib/monetra/active_support/core_ext/numeric.rb +7 -0
- data/lib/monetra/active_support/core_ext/numeric/bytes.rb +44 -0
- data/lib/monetra/active_support/core_ext/numeric/time.rb +72 -0
- data/lib/monetra/active_support/core_ext/object.rb +2 -0
- data/lib/monetra/active_support/core_ext/object/extending.rb +47 -0
- data/lib/monetra/active_support/core_ext/object/misc.rb +34 -0
- data/lib/monetra/active_support/core_ext/pathname.rb +7 -0
- data/lib/monetra/active_support/core_ext/pathname/clean_within.rb +14 -0
- data/lib/monetra/active_support/core_ext/proc.rb +12 -0
- data/lib/monetra/active_support/core_ext/range.rb +5 -0
- data/lib/monetra/active_support/core_ext/range/conversions.rb +21 -0
- data/lib/monetra/active_support/core_ext/string.rb +13 -0
- data/lib/monetra/active_support/core_ext/string/access.rb +58 -0
- data/lib/monetra/active_support/core_ext/string/conversions.rb +19 -0
- data/lib/monetra/active_support/core_ext/string/inflections.rb +153 -0
- data/lib/monetra/active_support/core_ext/string/iterators.rb +17 -0
- data/lib/monetra/active_support/core_ext/string/starts_ends_with.rb +20 -0
- data/lib/monetra/active_support/core_ext/symbol.rb +12 -0
- data/lib/monetra/active_support/core_ext/time.rb +7 -0
- data/lib/monetra/active_support/core_ext/time/calculations.rb +188 -0
- data/lib/monetra/active_support/core_ext/time/conversions.rb +36 -0
- data/lib/monetra/active_support/dependencies.rb +187 -0
- data/lib/monetra/active_support/deprecation.rb +106 -0
- data/lib/monetra/active_support/inflections.rb +53 -0
- data/lib/monetra/active_support/inflector.rb +179 -0
- data/lib/monetra/active_support/json.rb +37 -0
- data/lib/monetra/active_support/json/encoders.rb +25 -0
- data/lib/monetra/active_support/json/encoders/core.rb +65 -0
- data/lib/monetra/active_support/option_merger.rb +25 -0
- data/lib/monetra/active_support/ordered_options.rb +50 -0
- data/lib/monetra/active_support/reloadable.rb +30 -0
- data/lib/monetra/active_support/values/time_zone.rb +180 -0
- data/lib/monetra/active_support/vendor/builder.rb +13 -0
- data/lib/monetra/active_support/vendor/builder/blankslate.rb +63 -0
- data/lib/monetra/active_support/vendor/builder/xchar.rb +112 -0
- data/lib/monetra/active_support/vendor/builder/xmlbase.rb +145 -0
- data/lib/monetra/active_support/vendor/builder/xmlevents.rb +63 -0
- data/lib/monetra/active_support/vendor/builder/xmlmarkup.rb +328 -0
- data/lib/monetra/active_support/vendor/flexmock.rb +84 -0
- data/lib/monetra/active_support/vendor/xml_simple.rb +1019 -0
- data/lib/monetra/active_support/version.rb +9 -0
- data/lib/monetra/active_support/whiny_nil.rb +38 -0
- data/test/test.rb +21 -0
- metadata +167 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module ActiveSupport #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Hash #:nodoc:
|
4
|
+
# Allows for reverse merging where its the keys in the calling hash that wins over those in the <tt>other_hash</tt>.
|
5
|
+
# This is particularly useful for initializing an incoming option hash with default values:
|
6
|
+
#
|
7
|
+
# def setup(options = {})
|
8
|
+
# options.reverse_merge! :size => 25, :velocity => 10
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# The default :size and :velocity is only set if the +options+ passed in doesn't already have those keys set.
|
12
|
+
module ReverseMerge
|
13
|
+
def reverse_merge(other_hash)
|
14
|
+
other_hash.merge(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reverse_merge!(other_hash)
|
18
|
+
replace(reverse_merge(other_hash))
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :reverse_update, :reverse_merge
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActiveSupport #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Integer #:nodoc:
|
4
|
+
# For checking if a fixnum is even or odd.
|
5
|
+
# * 1.even? # => false
|
6
|
+
# * 1.odd? # => true
|
7
|
+
# * 2.even? # => true
|
8
|
+
# * 2.odd? # => false
|
9
|
+
module EvenOdd
|
10
|
+
def multiple_of?(number)
|
11
|
+
self % number == 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def even?
|
15
|
+
multiple_of? 2
|
16
|
+
end
|
17
|
+
|
18
|
+
def odd?
|
19
|
+
!even?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../inflector' unless defined? Inflector
|
2
|
+
module ActiveSupport #:nodoc:
|
3
|
+
module CoreExtensions #:nodoc:
|
4
|
+
module Integer #:nodoc:
|
5
|
+
module Inflections
|
6
|
+
# 1.ordinalize # => "1st"
|
7
|
+
# 3.ordinalize # => "3rd"
|
8
|
+
# 10.ordinalize # => "10th"
|
9
|
+
def ordinalize
|
10
|
+
Inflector.ordinalize(self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Object
|
2
|
+
# Makes backticks behave (somewhat more) similarly on all platforms.
|
3
|
+
# On win32 `nonexistent_command` raises Errno::ENOENT; on Unix, the
|
4
|
+
# spawned shell prints a message to stderr and sets $?. We emulate
|
5
|
+
# Unix on the former but not the latter.
|
6
|
+
def `(command) #:nodoc:
|
7
|
+
super
|
8
|
+
rescue Errno::ENOENT => e
|
9
|
+
STDERR.puts "#$0: #{e}"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Kernel
|
2
|
+
# Turns the current script into a daemon process that detaches from the console.
|
3
|
+
# It can be shut down with a TERM signal.
|
4
|
+
def daemonize
|
5
|
+
exit if fork # Parent exits, child continues.
|
6
|
+
Process.setsid # Become session leader.
|
7
|
+
exit if fork # Zap session leader. See [1].
|
8
|
+
Dir.chdir "/" # Release old working directory.
|
9
|
+
File.umask 0000 # Ensure sensible umask. Adjust as needed.
|
10
|
+
STDIN.reopen "/dev/null" # Free file descriptors and
|
11
|
+
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
|
12
|
+
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
|
13
|
+
trap("TERM") { exit }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Kernel
|
2
|
+
# Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
|
3
|
+
#
|
4
|
+
# silence_warnings do
|
5
|
+
# value = noisy_call # no warning voiced
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# noisy_call # warning voiced
|
9
|
+
def silence_warnings
|
10
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
11
|
+
yield
|
12
|
+
ensure
|
13
|
+
$VERBOSE = old_verbose
|
14
|
+
end
|
15
|
+
|
16
|
+
# Sets $VERBOSE to true for the duration of the block and back to its original value afterwards.
|
17
|
+
def enable_warnings
|
18
|
+
old_verbose, $VERBOSE = $VERBOSE, true
|
19
|
+
yield
|
20
|
+
ensure
|
21
|
+
$VERBOSE = old_verbose
|
22
|
+
end
|
23
|
+
|
24
|
+
# For compatibility
|
25
|
+
def silence_stderr #:nodoc:
|
26
|
+
silence_stream(STDERR) { yield }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Silences any stream for the duration of the block.
|
30
|
+
#
|
31
|
+
# silence_stream(STDOUT) do
|
32
|
+
# puts 'This will never be seen'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# puts 'But this will'
|
36
|
+
def silence_stream(stream)
|
37
|
+
old_stream = stream.dup
|
38
|
+
stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
|
39
|
+
stream.sync = true
|
40
|
+
yield
|
41
|
+
ensure
|
42
|
+
stream.reopen(old_stream)
|
43
|
+
end
|
44
|
+
|
45
|
+
def suppress(*exception_classes)
|
46
|
+
begin yield
|
47
|
+
rescue Exception => e
|
48
|
+
raise unless exception_classes.any? { |cls| e.kind_of?(cls) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kernel
|
2
|
+
# Require a library with fallback to RubyGems. Warnings during library
|
3
|
+
# loading are silenced to increase signal/noise for application warnings.
|
4
|
+
def require_library_or_gem(library_name)
|
5
|
+
silence_warnings do
|
6
|
+
begin
|
7
|
+
require library_name
|
8
|
+
rescue LoadError => cannot_require
|
9
|
+
# 1. Requiring the module is unsuccessful, maybe it's a gem and nobody required rubygems yet. Try.
|
10
|
+
begin
|
11
|
+
require 'rubygems'
|
12
|
+
rescue LoadError => rubygems_not_installed
|
13
|
+
raise cannot_require
|
14
|
+
end
|
15
|
+
# 2. Rubygems is installed and loaded. Try to load the library again
|
16
|
+
begin
|
17
|
+
require library_name
|
18
|
+
rescue LoadError => gem_not_installed
|
19
|
+
raise cannot_require
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class MissingSourceFile < LoadError #:nodoc:
|
2
|
+
attr_reader :path
|
3
|
+
def initialize(message, path)
|
4
|
+
super(message)
|
5
|
+
@path = path
|
6
|
+
end
|
7
|
+
|
8
|
+
def is_missing?(path)
|
9
|
+
path.gsub(/\.rb$/, '') == self.path.gsub(/\.rb$/, '')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_message(message)
|
13
|
+
REGEXPS.each do |regexp, capture|
|
14
|
+
match = regexp.match(message)
|
15
|
+
return MissingSourceFile.new(message, match[capture]) unless match.nil?
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
REGEXPS = [
|
21
|
+
[/^no such file to load -- (.+)$/i, 1],
|
22
|
+
[/^Missing \w+ (file\s*)?([^\s]+.rb)$/i, 2],
|
23
|
+
[/^Missing API definition file in (.+)$/i, 1]
|
24
|
+
] unless defined?(REGEXPS)
|
25
|
+
end
|
26
|
+
|
27
|
+
module ActiveSupport #:nodoc:
|
28
|
+
module CoreExtensions #:nodoc:
|
29
|
+
module LoadErrorExtensions #:nodoc:
|
30
|
+
module LoadErrorClassMethods #:nodoc:
|
31
|
+
def new(*args)
|
32
|
+
(self == LoadError && MissingSourceFile.from_message(args.first)) || super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
::LoadError.extend(LoadErrorClassMethods)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Adds the 'around_level' method to Logger.
|
2
|
+
|
3
|
+
class Logger
|
4
|
+
def self.define_around_helper(level)
|
5
|
+
module_eval <<-end_eval
|
6
|
+
def around_#{level}(before_message, after_message, &block)
|
7
|
+
self.#{level}(before_message)
|
8
|
+
return_value = block.call(self)
|
9
|
+
self.#{level}(after_message)
|
10
|
+
return return_value
|
11
|
+
end
|
12
|
+
end_eval
|
13
|
+
end
|
14
|
+
[:debug, :info, :error, :fatal].each {|level| define_around_helper(level) }
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/module/inclusion'
|
2
|
+
require File.dirname(__FILE__) + '/module/attribute_accessors'
|
3
|
+
require File.dirname(__FILE__) + '/module/attr_internal'
|
4
|
+
require File.dirname(__FILE__) + '/module/delegation'
|
5
|
+
require File.dirname(__FILE__) + '/module/introspection'
|
6
|
+
require File.dirname(__FILE__) + '/module/loading'
|
7
|
+
require File.dirname(__FILE__) + '/module/aliasing'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Module
|
2
|
+
# Encapsulates the common pattern of:
|
3
|
+
#
|
4
|
+
# alias_method :foo_without_feature, :foo
|
5
|
+
# alias_method :foo, :foo_with_feature
|
6
|
+
#
|
7
|
+
# With this, you simply do:
|
8
|
+
#
|
9
|
+
# alias_method_chain :foo, :feature
|
10
|
+
#
|
11
|
+
# And both aliases are set up for you.
|
12
|
+
#
|
13
|
+
# Query and bang methods (foo?, foo!) keep the same punctuation:
|
14
|
+
#
|
15
|
+
# alias_method_chain :foo?, :feature
|
16
|
+
#
|
17
|
+
# is equivalent to
|
18
|
+
#
|
19
|
+
# alias_method :foo_without_feature?, :foo?
|
20
|
+
# alias_method :foo?, :foo_with_feature?
|
21
|
+
#
|
22
|
+
# so you can safely chain foo, foo?, and foo! with the same feature.
|
23
|
+
def alias_method_chain(target, feature)
|
24
|
+
# Strip out punctuation on predicates or bang methods since
|
25
|
+
# e.g. target?_without_feature is not a valid method name.
|
26
|
+
aliased_target, punctuation = target.to_s.sub(/([?!])$/, ''), $1
|
27
|
+
alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target
|
28
|
+
alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Allows you to make aliases for attributes, which includes
|
32
|
+
# getter, setter, and query methods.
|
33
|
+
#
|
34
|
+
# Example:
|
35
|
+
#
|
36
|
+
# class Content < ActiveRecord::Base
|
37
|
+
# # has a title attribute
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# class Email < ActiveRecord::Base
|
41
|
+
# alias_attribute :subject, :title
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# e = Email.find(1)
|
45
|
+
# e.title # => "Superstars"
|
46
|
+
# e.subject # => "Superstars"
|
47
|
+
# e.subject? # => true
|
48
|
+
# e.subject = "Megastars"
|
49
|
+
# e.title # => "Megastars"
|
50
|
+
def alias_attribute(new_name, old_name)
|
51
|
+
module_eval <<-STR, __FILE__, __LINE__+1
|
52
|
+
def #{new_name}; #{old_name}; end
|
53
|
+
def #{new_name}?; #{old_name}?; end
|
54
|
+
def #{new_name}=(v); self.#{old_name} = v; end
|
55
|
+
STR
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Module
|
2
|
+
# Declare an attribute reader backed by an internally-named instance variable.
|
3
|
+
def attr_internal_reader(*attrs)
|
4
|
+
attrs.each do |attr|
|
5
|
+
module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Declare an attribute writer backed by an internally-named instance variable.
|
10
|
+
def attr_internal_writer(*attrs)
|
11
|
+
attrs.each do |attr|
|
12
|
+
module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Declare attributes backed by 'internal' instance variables names.
|
17
|
+
def attr_internal_accessor(*attrs)
|
18
|
+
attr_internal_reader *attrs
|
19
|
+
attr_internal_writer *attrs
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :attr_internal, :attr_internal_accessor
|
23
|
+
|
24
|
+
private
|
25
|
+
mattr_accessor :attr_internal_naming_format
|
26
|
+
self.attr_internal_naming_format = '@_%s'
|
27
|
+
|
28
|
+
def attr_internal_ivar_name(attr)
|
29
|
+
attr_internal_naming_format % attr
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Extends the module object with module and instance accessors for class attributes,
|
2
|
+
# just like the native attr* accessors for instance attributes.
|
3
|
+
class Module # :nodoc:
|
4
|
+
def mattr_reader(*syms)
|
5
|
+
syms.each do |sym|
|
6
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
7
|
+
unless defined? @@#{sym}
|
8
|
+
@@#{sym} = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.#{sym}
|
12
|
+
@@#{sym}
|
13
|
+
end
|
14
|
+
|
15
|
+
def #{sym}
|
16
|
+
@@#{sym}
|
17
|
+
end
|
18
|
+
EOS
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def mattr_writer(*syms)
|
23
|
+
syms.each do |sym|
|
24
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
25
|
+
unless defined? @@#{sym}
|
26
|
+
@@#{sym} = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.#{sym}=(obj)
|
30
|
+
@@#{sym} = obj
|
31
|
+
end
|
32
|
+
|
33
|
+
def #{sym}=(obj)
|
34
|
+
@@#{sym} = obj
|
35
|
+
end
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def mattr_accessor(*syms)
|
41
|
+
mattr_reader(*syms)
|
42
|
+
mattr_writer(*syms)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Module
|
2
|
+
# Provides a delegate class method to easily expose contained objects' methods
|
3
|
+
# as your own. Pass one or more methods (specified as symbols or strings)
|
4
|
+
# and the name of the target object as the final :to option (also a symbol
|
5
|
+
# or string). At least one method and the :to option are required.
|
6
|
+
#
|
7
|
+
# Delegation is particularly useful with Active Record associations:
|
8
|
+
# class Greeter < ActiveRecord::Base
|
9
|
+
# def hello() "hello" end
|
10
|
+
# def goodbye() "goodbye" end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# class Foo < ActiveRecord::Base
|
14
|
+
# belongs_to :greeter
|
15
|
+
# delegate :hello, :to => :greeter
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Foo.new.hello # => "hello"
|
19
|
+
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
|
20
|
+
#
|
21
|
+
# Multiple delegates to the same target are allowed:
|
22
|
+
# class Foo < ActiveRecord::Base
|
23
|
+
# delegate :hello, :goodbye, :to => :greeter
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# Foo.new.goodbye # => "goodbye"
|
27
|
+
def delegate(*methods)
|
28
|
+
options = methods.pop
|
29
|
+
unless options.is_a?(Hash) && to = options[:to]
|
30
|
+
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
|
31
|
+
end
|
32
|
+
|
33
|
+
methods.each do |method|
|
34
|
+
module_eval(<<-EOS, "(__DELEGATION__)", 1)
|
35
|
+
def #{method}(*args, &block)
|
36
|
+
#{to}.__send__(#{method.inspect}, *args, &block)
|
37
|
+
end
|
38
|
+
EOS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Module
|
2
|
+
def included_in_classes
|
3
|
+
classes = []
|
4
|
+
ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) }
|
5
|
+
|
6
|
+
classes.reverse.inject([]) do |unique_classes, klass|
|
7
|
+
unique_classes << klass unless unique_classes.collect { |k| k.to_s }.include?(klass.to_s)
|
8
|
+
unique_classes
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|