ruby_ext 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +64 -0
- data/lib/ruby_ext/array.rb +13 -0
- data/lib/ruby_ext/basic_object.rb +22 -0
- data/lib/ruby_ext/class.rb +11 -0
- data/lib/ruby_ext/declarative_cache.rb +85 -0
- data/lib/ruby_ext/deep_clone.rb +62 -0
- data/lib/ruby_ext/extra_blank_slate.rb +16 -0
- data/lib/ruby_ext/file.rb +20 -0
- data/lib/ruby_ext/hash.rb +15 -0
- data/lib/ruby_ext/kernel.rb +69 -0
- data/lib/ruby_ext/micelaneous.rb +14 -0
- data/lib/ruby_ext/module.rb +119 -0
- data/lib/ruby_ext/multiple_inheritance.rb +76 -0
- data/lib/ruby_ext/must.rb +192 -0
- data/lib/ruby_ext/not_defined.rb +2 -0
- data/lib/ruby_ext/object.rb +8 -0
- data/lib/ruby_ext/observable2.rb +23 -0
- data/lib/ruby_ext/open_constructor.rb +51 -0
- data/lib/ruby_ext/open_object.rb +157 -0
- data/lib/ruby_ext/prepare_arguments.rb +105 -0
- data/lib/ruby_ext/prototype_inheritance.rb +110 -0
- data/lib/ruby_ext/should.rb +166 -0
- data/lib/ruby_ext/string.rb +44 -0
- data/lib/ruby_ext/symbol.rb +21 -0
- data/lib/ruby_ext/synchronize.rb +24 -0
- data/lib/ruby_ext/tuple.rb +7 -0
- data/lib/ruby_ext.rb +50 -0
- data/lib/spec_ext.rb +10 -0
- data/readme.md +66 -0
- data/spec/_prototype_inheritance_spec.rb +190 -0
- data/spec/array_spec.rb +8 -0
- data/spec/declarative_cache_spec.rb +115 -0
- data/spec/deep_clone_spec.rb +37 -0
- data/spec/helper.rb +20 -0
- data/spec/kernel_spec/TheNamespace/ClassA.rb +7 -0
- data/spec/kernel_spec/another_class.rb +5 -0
- data/spec/kernel_spec/the_namespace/class_b.rb +11 -0
- data/spec/kernel_spec.rb +53 -0
- data/spec/module_spec.rb +160 -0
- data/spec/multiple_inheritance_spec.rb +131 -0
- data/spec/must_spec.rb +29 -0
- data/spec/observable2_spec.rb +42 -0
- data/spec/open_constructor_spec.rb +36 -0
- data/spec/open_object_spec.rb +29 -0
- data/spec/prepare_arguments_spec.rb +46 -0
- data/spec/should_spec.rb +24 -0
- data/spec/spec.opts +2 -0
- data/spec/synchronize_spec.rb +80 -0
- metadata +127 -0
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'fileutils'
|
3
|
+
current_dir = File.expand_path(File.dirname(__FILE__))
|
4
|
+
Dir.chdir current_dir
|
5
|
+
|
6
|
+
|
7
|
+
#
|
8
|
+
# Specs
|
9
|
+
#
|
10
|
+
require 'spec/rake/spectask'
|
11
|
+
|
12
|
+
task :default => :spec
|
13
|
+
|
14
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
15
|
+
t.spec_files = FileList["spec/**/*_spec.rb"].select{|f| f !~ /\/_/}
|
16
|
+
t.libs = ["#{current_dir}/lib"]
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
# Gem
|
22
|
+
#
|
23
|
+
require 'rake/clean'
|
24
|
+
require 'rake/gempackagetask'
|
25
|
+
|
26
|
+
gem_options = {
|
27
|
+
:name => "ruby_ext",
|
28
|
+
:version => "0.4.6",
|
29
|
+
:summary => "Ruby language extensions",
|
30
|
+
:dependencies => %w(facets)
|
31
|
+
}
|
32
|
+
|
33
|
+
spec = Gem::Specification.new do |s|
|
34
|
+
gem_options.delete(:dependencies).each{|d| s.add_dependency d}
|
35
|
+
gem_options.each{|k, v| s.send "#{k}=", v}
|
36
|
+
|
37
|
+
s.author = "Alexey Petrushin"
|
38
|
+
s.homepage = "http://github.com/alexeypetrushin/#{gem_options[:name]}"
|
39
|
+
s.require_path = "lib"
|
40
|
+
s.files = (%w{Rakefile readme.md} + Dir.glob("{lib,spec}/**/*"))
|
41
|
+
|
42
|
+
s.platform = Gem::Platform::RUBY
|
43
|
+
s.has_rdoc = true
|
44
|
+
end
|
45
|
+
|
46
|
+
package_dir = "#{current_dir}/build"
|
47
|
+
Rake::GemPackageTask.new(spec) do |p|
|
48
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
49
|
+
p.need_zip = true
|
50
|
+
p.package_dir = package_dir
|
51
|
+
end
|
52
|
+
|
53
|
+
task :push do
|
54
|
+
# dir = Dir.chdir package_dir do
|
55
|
+
gem_file = Dir.glob("#{package_dir}/#{gem_options[:name]}*.gem").first
|
56
|
+
system "gem push #{gem_file}"
|
57
|
+
# end
|
58
|
+
end
|
59
|
+
|
60
|
+
task :clean do
|
61
|
+
system "rm -r #{package_dir}"
|
62
|
+
end
|
63
|
+
|
64
|
+
task :release => [:gem, :push, :clean]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Array
|
2
|
+
def sfilter *filters
|
3
|
+
filters = filters.first if filters.size == 1 and filters.first.is_a?(Array)
|
4
|
+
filters.collect!{|o| o.is_a?(Regexp) ? o : /#{Regexp.escape o}/}
|
5
|
+
self.select do |line|
|
6
|
+
!filters.any?{|re| line =~ re}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.wrap value
|
11
|
+
Array(value)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
if defined? ::BasicObject
|
2
|
+
# A class with no predefined methods that behaves similarly to Builder's
|
3
|
+
# BlankSlate. Used for proxy classes.
|
4
|
+
class BasicObject < ::BasicObject
|
5
|
+
begin
|
6
|
+
undef_method :==
|
7
|
+
undef_method :equal?
|
8
|
+
rescue
|
9
|
+
end
|
10
|
+
|
11
|
+
# Let ActiveSupport::BasicObject at least raise exceptions.
|
12
|
+
def raise(*args)
|
13
|
+
::Object.send(:raise, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
else
|
17
|
+
class BasicObject #:nodoc:
|
18
|
+
instance_methods.each do |m|
|
19
|
+
undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
class Module
|
4
|
+
def cache_method *methods
|
5
|
+
DeclarativeCache.cache_method self, *methods
|
6
|
+
end
|
7
|
+
|
8
|
+
def cache_method_with_params *methods
|
9
|
+
DeclarativeCache.cache_method_with_params self, *methods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Object
|
14
|
+
def clear_cache_method
|
15
|
+
instance_variables.each do |iv|
|
16
|
+
remove_instance_variable iv if iv =~ /^@cached_/
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module DeclarativeCache
|
22
|
+
DISABLED = false
|
23
|
+
|
24
|
+
warn "CASHE DISABLED" if DISABLED
|
25
|
+
unless DISABLED
|
26
|
+
class << self
|
27
|
+
|
28
|
+
def cache_method klass, *methods
|
29
|
+
methods.each do |method|
|
30
|
+
klass.class_eval do
|
31
|
+
als = "cached_#{escape_method(method)}"
|
32
|
+
iv_check = "@#{als}_check"
|
33
|
+
iv = "@#{als}"
|
34
|
+
|
35
|
+
raise "Can't cache the #{method} twice!" if instance_methods.include?(als)
|
36
|
+
|
37
|
+
alias_method als, method
|
38
|
+
|
39
|
+
define_method method do |*args|
|
40
|
+
raise "You tried to use cache without params for method with params (use 'cache_method_with_params' instead)!" unless args.empty?
|
41
|
+
unless cached = instance_variable_get(iv)
|
42
|
+
unless check = instance_variable_get(iv_check)
|
43
|
+
cached = send als
|
44
|
+
instance_variable_set iv, cached
|
45
|
+
instance_variable_set iv_check, true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
cached
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def cache_method_with_params klass, *methods
|
55
|
+
methods.each do |method|
|
56
|
+
klass.class_eval do
|
57
|
+
als = "cached_#{escape_method(method)}"
|
58
|
+
iv = "@#{als}"
|
59
|
+
|
60
|
+
raise "Can't cache the '#{method}' twice!" if instance_methods.include?(als)
|
61
|
+
|
62
|
+
alias_method als, method
|
63
|
+
|
64
|
+
define_method method do |*args|
|
65
|
+
unless results = instance_variable_get(iv)
|
66
|
+
results = Hash.new(NotDefined)
|
67
|
+
instance_variable_set iv, results
|
68
|
+
end
|
69
|
+
|
70
|
+
result = results[args]
|
71
|
+
|
72
|
+
if result.equal? NotDefined
|
73
|
+
result = send als, *args
|
74
|
+
results[args] = result
|
75
|
+
end
|
76
|
+
|
77
|
+
result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class Object
|
2
|
+
def deep_clone
|
3
|
+
clone = self.clone
|
4
|
+
instance_variables.each do |name|
|
5
|
+
value = instance_variable_get name
|
6
|
+
clone.instance_variable_set name, value.deep_clone
|
7
|
+
end
|
8
|
+
clone
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Hash.class_eval do
|
13
|
+
def deep_clone
|
14
|
+
clone = super
|
15
|
+
clone.clear
|
16
|
+
each{|k, v| clone[k.deep_clone] = v.deep_clone}
|
17
|
+
clone
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
OpenObject.class_eval do
|
22
|
+
def deep_clone
|
23
|
+
clone = super
|
24
|
+
clone.clear
|
25
|
+
each{|k, v| clone[k.deep_clone] = v.deep_clone}
|
26
|
+
clone
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Struct.class_eval do
|
31
|
+
def deep_clone
|
32
|
+
clone = super
|
33
|
+
clone.clear
|
34
|
+
each_pair{|k, v| clone[k.deep_clone] = v.deep_clone}
|
35
|
+
clone
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Array.class_eval do
|
40
|
+
def deep_clone
|
41
|
+
clone = super
|
42
|
+
clone.clear
|
43
|
+
each{|v| clone << v.deep_clone}
|
44
|
+
clone
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
[Class, Proc].each do |klass|
|
49
|
+
klass.class_eval do
|
50
|
+
def deep_clone
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
[Symbol, TrueClass, FalseClass, Numeric, TrueClass, FalseClass, NilClass].each do |klass|
|
57
|
+
klass.send :alias_method, :clone, :self
|
58
|
+
end
|
59
|
+
|
60
|
+
[String, Symbol, Range, Regexp, Time, Date].each do |klass|
|
61
|
+
klass.send :alias_method, :deep_clone, :clone
|
62
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ExtraBlankSlate
|
2
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
3
|
+
|
4
|
+
CUSTOM_UNDEFINE = [:p, :select, :puts]
|
5
|
+
|
6
|
+
undefine = Kernel.instance_methods + Object.instance_methods + CUSTOM_UNDEFINE
|
7
|
+
ExtraBlankSlate.instance_methods.each{|m| undefine.delete m}
|
8
|
+
|
9
|
+
undefine.each do |m|
|
10
|
+
script = %{\
|
11
|
+
def #{m} *p, &b
|
12
|
+
method_missing :#{m}, *p, &b
|
13
|
+
end}
|
14
|
+
class_eval script, __FILE__, __LINE__
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
File.class_eval do
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def write(path, data)
|
7
|
+
File.open(path, "wb") do |file|
|
8
|
+
return file.write(data)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_directory dir
|
13
|
+
FileUtils.mkdir_p dir unless File.exist? dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete_directory dir
|
17
|
+
FileUtils.rm_r dir, :force => true if File.exist? dir
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
Kernel.class_eval do
|
2
|
+
def respond_to sym, *args
|
3
|
+
return nil if not respond_to? sym
|
4
|
+
send sym, *args
|
5
|
+
end
|
6
|
+
|
7
|
+
# def _ &b
|
8
|
+
# raise "Block isn't provided!" unless b
|
9
|
+
# return b
|
10
|
+
# end
|
11
|
+
|
12
|
+
def singleton_class(&block)
|
13
|
+
if block_given?
|
14
|
+
(class << self; self; end).class_eval(&block)
|
15
|
+
self
|
16
|
+
else
|
17
|
+
(class << self; self; end)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias_method :metaclass, :singleton_class
|
21
|
+
alias_method :metaclass_eval, :singleton_class
|
22
|
+
|
23
|
+
# Removes the namespace (exact match and underscored) of given class (or self) from stacktrace
|
24
|
+
def raise_without_self *args
|
25
|
+
error, message, klasses = nil
|
26
|
+
if args.size == 1
|
27
|
+
error = RuntimeError
|
28
|
+
message = args[0]
|
29
|
+
klasses = [self]
|
30
|
+
elsif args.size == 2
|
31
|
+
message, klasses = args
|
32
|
+
error = RuntimeError
|
33
|
+
|
34
|
+
klasses = Array(klasses)
|
35
|
+
klasses << self
|
36
|
+
elsif args.size == 3
|
37
|
+
error, message, klasses = args
|
38
|
+
|
39
|
+
klasses = Array(klasses)
|
40
|
+
klasses << self
|
41
|
+
else
|
42
|
+
raise RuntimeError, "Invalid arguments!", caller
|
43
|
+
end
|
44
|
+
|
45
|
+
klasses.collect!{|c| (c.class == Class or c.class == Module or c.class == String) ? c : c.class}
|
46
|
+
|
47
|
+
# obtaining the namespace of each class
|
48
|
+
klasses.collect! do |c|
|
49
|
+
if c.respond_to? :namespace
|
50
|
+
c = c.namespace while c.namespace
|
51
|
+
c
|
52
|
+
else
|
53
|
+
c
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# building regexp
|
58
|
+
skip = []
|
59
|
+
klasses.each do |c|
|
60
|
+
skip.push(/\/#{c.to_s}/) # exact match
|
61
|
+
skip.push(/\/#{c.to_s.underscore}/) # underscored
|
62
|
+
end
|
63
|
+
|
64
|
+
# cleaning stacktrace
|
65
|
+
stack = caller.select{|path| !skip.any?{|re| re =~ path}}
|
66
|
+
|
67
|
+
raise error, message, stack
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
Module.class_eval do
|
4
|
+
def is?(base)
|
5
|
+
ancestors.include?(base)
|
6
|
+
end
|
7
|
+
|
8
|
+
def wrap_method( sym, prefix = "old_", &blk )
|
9
|
+
old_method = "#{prefix}_#{sym}".to_sym
|
10
|
+
alias_method old_method, sym
|
11
|
+
define_method(sym) do |*args|
|
12
|
+
instance_exec(old_method, *args, &blk)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def namespace
|
17
|
+
if @module_namespace_defined
|
18
|
+
@module_namespace
|
19
|
+
else
|
20
|
+
@module_namespace_defined = true
|
21
|
+
@module_namespace = Module.namespace_for name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_namespace &block
|
26
|
+
current = namespace
|
27
|
+
while current do
|
28
|
+
block.call current
|
29
|
+
current = current.namespace
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def each_ancestor include_standard = false, &block
|
34
|
+
if include_standard
|
35
|
+
ancestors.each{|a| block.call a unless a == self}
|
36
|
+
else
|
37
|
+
exclude = [self, Object, Kernel]
|
38
|
+
ancestors.each do |a|
|
39
|
+
block.call a unless exclude.include? a
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self_ancestors_and_namespaces &b
|
45
|
+
b.call self
|
46
|
+
each_ancestor &b
|
47
|
+
each_namespace &b
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.namespace_for class_name
|
51
|
+
list = class_name.split("::")
|
52
|
+
if list.size > 1
|
53
|
+
list.pop
|
54
|
+
return eval(list.join("::"), TOPLEVEL_BINDING, __FILE__, __LINE__)
|
55
|
+
else
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def inheritable_accessor attribute_name, default_value
|
61
|
+
raise "Can be used only for Class and Module" unless self.class.is? Module
|
62
|
+
# raise "Default value can't be nil!" unless default_value
|
63
|
+
|
64
|
+
iv_name = "@#{attribute_name}"
|
65
|
+
iv_defined = "@#{attribute_name}_defined"
|
66
|
+
|
67
|
+
define_method attribute_name do
|
68
|
+
unless instance_variable_get(iv_defined)
|
69
|
+
iv = nil
|
70
|
+
ancestors[1..-1].each do |a|
|
71
|
+
if a.respond_to?(attribute_name) and (value = a.send(attribute_name))
|
72
|
+
iv = value.deep_clone
|
73
|
+
break
|
74
|
+
end
|
75
|
+
end
|
76
|
+
iv ||= default_value.deep_clone
|
77
|
+
instance_variable_set iv_name, iv
|
78
|
+
instance_variable_set iv_defined, true
|
79
|
+
iv
|
80
|
+
else
|
81
|
+
instance_variable_get iv_name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
define_method "#{attribute_name}=" do |value|
|
86
|
+
# raise "Value can't be nil!" unless value
|
87
|
+
instance_variable_set iv_name, value
|
88
|
+
instance_variable_set iv_defined, true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
raise "Internal error, it shouldn't be loaded twice!" if defined? ESCAPE_METHOD_SYMBOLS # some tricky error when runing spec with rake
|
93
|
+
ESCAPE_METHOD_SYMBOLS = [
|
94
|
+
['==', 'assign'],
|
95
|
+
['>', 'gt'],
|
96
|
+
['<', 'lt'],
|
97
|
+
['>=', 'gte'],
|
98
|
+
['<=', 'lte'],
|
99
|
+
['?', 'qst'],
|
100
|
+
['!', 'imp'],
|
101
|
+
['<=>', 'lorg'],
|
102
|
+
['*', 'mp'],
|
103
|
+
['+', 'add'],
|
104
|
+
['-', 'sub'],
|
105
|
+
['=', 'assign'],
|
106
|
+
['**', 'pw'],
|
107
|
+
['=~', 'sim'],
|
108
|
+
['[]', 'sb'],
|
109
|
+
]
|
110
|
+
|
111
|
+
def escape_method method
|
112
|
+
m = method.to_s.clone
|
113
|
+
ESCAPE_METHOD_SYMBOLS.each{|from, to| m.gsub! from, to}
|
114
|
+
raise "Invalid method name '#{method}'!" unless m =~ /^[_a-zA-Z0-9]+$/
|
115
|
+
m
|
116
|
+
end
|
117
|
+
|
118
|
+
public :include
|
119
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# Fix for ruby's broken include.
|
3
|
+
# Included modules doesn't propagated to it's children.
|
4
|
+
#
|
5
|
+
# Test case:
|
6
|
+
# module A; end
|
7
|
+
# module B
|
8
|
+
# include A
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# module Plugin; end
|
12
|
+
# A.send(:include, Plugin)
|
13
|
+
#
|
14
|
+
# p "Ancestors of A: " + A.ancestors.join(', ') # => "Ancestors of A: A, Plugin"
|
15
|
+
# p "Ancestors of B: " + B.ancestors.join(', ') # => "Ancestors of B: B, A" << NO PLUGIN!
|
16
|
+
#
|
17
|
+
class Module
|
18
|
+
def directly_included_by
|
19
|
+
@directly_included_by ||= Set.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def fixed_include mod
|
23
|
+
unless mod.directly_included_by.include? self
|
24
|
+
mod.directly_included_by.add self
|
25
|
+
end
|
26
|
+
|
27
|
+
include mod
|
28
|
+
directly_included_by.each do |child|
|
29
|
+
child.fixed_include self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
#
|
36
|
+
# Inheritance
|
37
|
+
#
|
38
|
+
class Module
|
39
|
+
def class_prototype
|
40
|
+
unless @class_prototype
|
41
|
+
unless const_defined? :ClassMethods
|
42
|
+
class_eval "module ClassMethods; end", __FILE__, __LINE__
|
43
|
+
end
|
44
|
+
@class_prototype = const_get :ClassMethods
|
45
|
+
|
46
|
+
(class << self; self end).fixed_include @class_prototype
|
47
|
+
end
|
48
|
+
@class_prototype
|
49
|
+
end
|
50
|
+
|
51
|
+
def class_methods &block
|
52
|
+
if block
|
53
|
+
class_prototype.class_eval &block
|
54
|
+
extend class_prototype
|
55
|
+
else
|
56
|
+
class_prototype.instance_methods
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def inherit *modules
|
61
|
+
modules.each do |mod|
|
62
|
+
# Instance Methods
|
63
|
+
fixed_include mod
|
64
|
+
|
65
|
+
# Class Methods
|
66
|
+
if self.class == Module
|
67
|
+
class_prototype.fixed_include mod.class_prototype
|
68
|
+
else
|
69
|
+
(class << self; self end).fixed_include mod.class_prototype
|
70
|
+
end
|
71
|
+
|
72
|
+
# callback
|
73
|
+
mod.inherited self if mod.respond_to? :inherited
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|