utilrb 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes.txt +20 -0
- data/License.txt +26 -0
- data/Manifest.txt +64 -0
- data/README.txt +44 -0
- data/Rakefile +46 -0
- data/bm/allocation.rb +7 -0
- data/bm/speed.rb +19 -0
- data/ext/extconf.rb +5 -0
- data/ext/faster.cc +48 -0
- data/ext/swap.cc +61 -0
- data/ext/value_set.cc +290 -0
- data/lib/utilrb.rb +2 -0
- data/lib/utilrb/array.rb +2 -0
- data/lib/utilrb/array/to_s.rb +16 -0
- data/lib/utilrb/common.rb +50 -0
- data/lib/utilrb/enumerable.rb +2 -0
- data/lib/utilrb/enumerable/null.rb +18 -0
- data/lib/utilrb/enumerable/random_element.rb +16 -0
- data/lib/utilrb/enumerable/sequence.rb +24 -0
- data/lib/utilrb/enumerable/uniq.rb +61 -0
- data/lib/utilrb/exception.rb +2 -0
- data/lib/utilrb/exception/full_message.rb +8 -0
- data/lib/utilrb/gc.rb +2 -0
- data/lib/utilrb/gc/force.rb +11 -0
- data/lib/utilrb/hash.rb +2 -0
- data/lib/utilrb/hash/slice.rb +6 -0
- data/lib/utilrb/hash/to_s.rb +6 -0
- data/lib/utilrb/hash/to_sym_keys.rb +6 -0
- data/lib/utilrb/kernel.rb +2 -0
- data/lib/utilrb/kernel/arity.rb +10 -0
- data/lib/utilrb/kernel/options.rb +69 -0
- data/lib/utilrb/kernel/poll.rb +24 -0
- data/lib/utilrb/kernel/require.rb +12 -0
- data/lib/utilrb/kernel/swap.rb +2 -0
- data/lib/utilrb/logger.rb +3 -0
- data/lib/utilrb/logger/forward.rb +15 -0
- data/lib/utilrb/logger/hierarchy.rb +34 -0
- data/lib/utilrb/module.rb +2 -0
- data/lib/utilrb/module/ancestor_p.rb +6 -0
- data/lib/utilrb/module/attr_enumerable.rb +28 -0
- data/lib/utilrb/module/define_method.rb +30 -0
- data/lib/utilrb/module/include.rb +30 -0
- data/lib/utilrb/module/inherited_enumerable.rb +122 -0
- data/lib/utilrb/object.rb +2 -0
- data/lib/utilrb/object/address.rb +14 -0
- data/lib/utilrb/object/attribute.rb +89 -0
- data/lib/utilrb/object/singleton_class.rb +53 -0
- data/lib/utilrb/objectstats.rb +52 -0
- data/lib/utilrb/time.rb +2 -0
- data/lib/utilrb/time/to_hms.rb +6 -0
- data/lib/utilrb/unbound_method.rb +2 -0
- data/lib/utilrb/unbound_method/call.rb +5 -0
- data/lib/utilrb/value_set.rb +17 -0
- data/test/test_array.rb +9 -0
- data/test/test_config.rb +4 -0
- data/test/test_enumerable.rb +89 -0
- data/test/test_gc.rb +39 -0
- data/test/test_hash.rb +22 -0
- data/test/test_kernel.rb +70 -0
- data/test/test_misc.rb +42 -0
- data/test/test_module.rb +127 -0
- data/test/test_object.rb +65 -0
- data/test/test_objectstats.rb +19 -0
- data/test/test_unbound_method.rb +23 -0
- metadata +128 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'utilrb/object/attribute'
|
2
|
+
|
3
|
+
class Module
|
4
|
+
# Define 'name' to be a read-only enumerable attribute. The method
|
5
|
+
# defines a +attr_name+ read-only attribute and an enumerator method
|
6
|
+
# each_#{name}. +init_block+ is used to initialize the attribute.
|
7
|
+
#
|
8
|
+
# The enumerator method accepts a +key+ argument. If the attribute is
|
9
|
+
# a key => enumerable map, then the +key+ attribute can be used to iterate
|
10
|
+
#
|
11
|
+
# +enumerator+ is the name of the enumeration method
|
12
|
+
def attr_enumerable(name, attr_name = name, enumerator = :each, &init_block)
|
13
|
+
class_eval do
|
14
|
+
attribute(attr_name, &init_block)
|
15
|
+
end
|
16
|
+
class_eval <<-EOF
|
17
|
+
def each_#{name}(key = nil, &iterator)
|
18
|
+
return unless #{attr_name}
|
19
|
+
if key
|
20
|
+
#{attr_name}[key].#{enumerator}(&iterator)
|
21
|
+
else
|
22
|
+
#{attr_name}.#{enumerator}(&iterator)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
EOF
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Module
|
2
|
+
# Emulate block-passing by converting the block into a Proc object
|
3
|
+
# and passing it to the given block as last argument
|
4
|
+
# dule)
|
5
|
+
#
|
6
|
+
# For instance
|
7
|
+
# define_method('my_method') do |a, &block|
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# Is written as
|
11
|
+
# define_method_with_block('my_method') do |block, a|
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# The block is given first to allow the following construct:
|
15
|
+
#
|
16
|
+
# define_method_with_block('my_method') do |block, *args|
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# +block+ is +nil+ if no block is given on the method call
|
20
|
+
#
|
21
|
+
def define_method_with_block(name, &mdef)
|
22
|
+
class_eval <<-EOD
|
23
|
+
def #{name}(*args, &block)
|
24
|
+
dmwb_#{name}_user_definition(block, *args)
|
25
|
+
end
|
26
|
+
EOD
|
27
|
+
define_method("dmwb_#{name}_user_definition", &mdef)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Module
|
2
|
+
unless (method(:__instance_include__) rescue nil)
|
3
|
+
alias :__instance_include__ :include
|
4
|
+
end
|
5
|
+
|
6
|
+
# Includes a module in this one, with support for class extensions
|
7
|
+
#
|
8
|
+
# If a module defines a ClassExtension submodule, then
|
9
|
+
# * if it is included in a module, the target's ClassExtension
|
10
|
+
# module includes the source ClassExtension (and if there is no
|
11
|
+
# ClassExtension in the target, it is created)
|
12
|
+
# * if it is included in a Class, the ClassExtension module
|
13
|
+
# extends the class.
|
14
|
+
def include(mod)
|
15
|
+
__instance_include__ mod
|
16
|
+
return unless mod.const_defined?(:ClassExtension)
|
17
|
+
|
18
|
+
if is_a?(Module) && !is_a?(Class)
|
19
|
+
unless const_defined?(:ClassExtension)
|
20
|
+
const_set(:ClassExtension, Module.new)
|
21
|
+
end
|
22
|
+
const_get(:ClassExtension).class_eval do
|
23
|
+
__instance_include__ mod.const_get(:ClassExtension)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
extend mod.const_get(:ClassExtension)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'utilrb/object/attribute'
|
2
|
+
require 'utilrb/object/singleton_class'
|
3
|
+
require 'utilrb/enumerable/uniq'
|
4
|
+
require 'utilrb/module/include'
|
5
|
+
|
6
|
+
class Module
|
7
|
+
def define_inherited_enumerable(name, attribute_name = name, options = Hash.new, &init) # :nodoc:
|
8
|
+
# Set up the attribute accessor
|
9
|
+
attribute(attribute_name, &init)
|
10
|
+
class_eval { private "#{attribute_name}=" }
|
11
|
+
|
12
|
+
options[:enum_with] ||= :each
|
13
|
+
|
14
|
+
if options[:map]
|
15
|
+
class_eval <<-EOF
|
16
|
+
def each_#{name}(key = nil, uniq = true)
|
17
|
+
if key
|
18
|
+
if #{attribute_name}.has_key?(key)
|
19
|
+
yield(#{attribute_name}[key])
|
20
|
+
return self if uniq
|
21
|
+
end
|
22
|
+
elsif uniq
|
23
|
+
@enum_#{name}_uniq ||= enum_uniq(:each_#{name}, nil, false) { |k, v| k }
|
24
|
+
@enum_#{name}_uniq.each { |el| yield(el) }
|
25
|
+
return self
|
26
|
+
else
|
27
|
+
#{attribute_name}.#{options[:enum_with]} { |el| yield(el) }
|
28
|
+
end
|
29
|
+
if superclass = ancestors[1..-1].find { |k| k.respond_to?(:each_#{name}) }
|
30
|
+
superclass.each_#{name}(key, uniq) { |el| yield(el) }
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
def has_#{name}?(key)
|
35
|
+
return true if #{attribute_name}[key]
|
36
|
+
if superclass = ancestors[1..-1].find { |k| k.respond_to?(:has_#{name}) }
|
37
|
+
superclass.has_#{name}(key)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
EOF
|
41
|
+
else
|
42
|
+
class_eval <<-EOF
|
43
|
+
def each_#{name}(&iterator)
|
44
|
+
#{attribute_name}.#{options[:enum_with]}(&iterator) if #{attribute_name}
|
45
|
+
if superclass = ancestors[1..-1].find { |k| k.respond_to?(:each_#{name}) }
|
46
|
+
superclass.each_#{name} { |el| yield(el) }
|
47
|
+
end
|
48
|
+
self
|
49
|
+
end
|
50
|
+
EOF
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Defines an attribute as being enumerable in the class instance and in the
|
55
|
+
# whole class inheritance hierarchy. More specifically, it defines a
|
56
|
+
# <tt>each_#{name}(&iterator)</tt> instance method and a <tt>each_#{name}(&iterator)</tt>
|
57
|
+
# class method which iterates (in order) on
|
58
|
+
# - the instance #{name} attribute
|
59
|
+
# - the singleton class #{name} attribute
|
60
|
+
# - the class #{name} attribute
|
61
|
+
# - the superclass #{name} attribute
|
62
|
+
# - the superclass' superclass #{name} attribute
|
63
|
+
# ...
|
64
|
+
#
|
65
|
+
# This method can be used on modules, in which case the module is used as if
|
66
|
+
# it was part of the inheritance hierarchy.
|
67
|
+
#
|
68
|
+
# The +name+ option defines the enumeration method name (+value+ will
|
69
|
+
# define a +each_value+ method). +attribute_name+ defines the attribute
|
70
|
+
# name. +init+ is a block called to initialize the attribute.
|
71
|
+
# Valid options in +options+ are:
|
72
|
+
# map:: the attribute should respond to +[]+. The enumeration method takes two
|
73
|
+
# arguments, +key+ and +uniq+. If +key+ is given, we iterate on the values
|
74
|
+
# given by <tt>attribute[key]</tt>. If +uniq+ is true, the enumeration will
|
75
|
+
# yield at most one value for each +key+ found (so, if both +key+ and +uniq+ are
|
76
|
+
# given, the enumeration yields at most one value)
|
77
|
+
#
|
78
|
+
# For instance
|
79
|
+
#
|
80
|
+
# class A
|
81
|
+
# class_inherited_enumerable("value", "enum") { Array.new }
|
82
|
+
# end
|
83
|
+
# module M
|
84
|
+
# inherited_enumerable("attr") { Array.new }
|
85
|
+
# end
|
86
|
+
# class B < A
|
87
|
+
# include M
|
88
|
+
# end
|
89
|
+
# b = B.new
|
90
|
+
#
|
91
|
+
# A.enum << 1
|
92
|
+
# B.enum << 2
|
93
|
+
# M.attr << 1
|
94
|
+
# class << b
|
95
|
+
# enum << 3
|
96
|
+
# attr << 4
|
97
|
+
# end
|
98
|
+
# M.attr << 2
|
99
|
+
#
|
100
|
+
# A.each_enum => 1
|
101
|
+
# B.each_enum => 2, 1
|
102
|
+
# b.singleton_class.each_enum => 3, 2, 1
|
103
|
+
# b.singleton_class.each_attr => 4, 1, 2
|
104
|
+
#
|
105
|
+
def inherited_enumerable(name, attribute_name = name, options = Hash.new, &init)
|
106
|
+
singleton_class.class_eval { define_inherited_enumerable(name, attribute_name, options, &init) }
|
107
|
+
|
108
|
+
if is_a?(Module) && !is_a?(Class)
|
109
|
+
unless const_defined?(:ClassExtension)
|
110
|
+
const_set(:ClassExtension, Module.new)
|
111
|
+
end
|
112
|
+
class_extension = const_get(:ClassExtension)
|
113
|
+
class_extension.class_eval do
|
114
|
+
define_inherited_enumerable(name, attribute_name, options, &init)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
class Object
|
3
|
+
# Return the object address (for non immediate
|
4
|
+
# objects).
|
5
|
+
def address; Object.address_from_id(object_id) end
|
6
|
+
|
7
|
+
# Converts the object_id of a non-immediate object
|
8
|
+
# to its 32 bits address
|
9
|
+
def self.address_from_id(id)
|
10
|
+
id = 0xFFFFFFFF - ~id if id < 0
|
11
|
+
(id * 2) & 0xFFFFFFFF
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'utilrb/common'
|
2
|
+
require 'utilrb/object/singleton_class'
|
3
|
+
|
4
|
+
Utilrb.unless_faster do
|
5
|
+
class Object
|
6
|
+
# :call-seq
|
7
|
+
# attribute :name => default_value
|
8
|
+
# attribute(:name) { default_value }
|
9
|
+
#
|
10
|
+
# In the first form, defines a read-write attribute
|
11
|
+
# named 'name' with default_value for default value.
|
12
|
+
# In the second form, the block is called if the attribute
|
13
|
+
# is read before it has been ever written, and its return
|
14
|
+
# value is used as default value.
|
15
|
+
def attribute(attr_def, &init)
|
16
|
+
if Hash === attr_def
|
17
|
+
name, defval = attr_def.to_a.flatten
|
18
|
+
else
|
19
|
+
name = attr_def
|
20
|
+
end
|
21
|
+
|
22
|
+
class_eval do
|
23
|
+
attr_writer name
|
24
|
+
define_method("#{name}_defval") do
|
25
|
+
defval || (instance_eval(&init) if init)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class_eval <<-EOD
|
30
|
+
def #{name}
|
31
|
+
if defined? @#{name} then @#{name}
|
32
|
+
else @#{name} = #{name}_defval
|
33
|
+
end
|
34
|
+
end
|
35
|
+
EOD
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Utilrb.if_faster do
|
41
|
+
class Object
|
42
|
+
# :call-seq
|
43
|
+
# attribute :name => default_value
|
44
|
+
# attribute(:name) { default_value }
|
45
|
+
#
|
46
|
+
# In the first form, defines a read-write attribute
|
47
|
+
# named 'name' with default_value for default value.
|
48
|
+
# In the second form, the block is called if the attribute
|
49
|
+
# is read before it has been ever written, and its return
|
50
|
+
# value is used as default value.
|
51
|
+
def attribute(attr_def, &init)
|
52
|
+
if Hash === attr_def
|
53
|
+
name, defval = attr_def.to_a.flatten
|
54
|
+
else
|
55
|
+
name = attr_def
|
56
|
+
end
|
57
|
+
|
58
|
+
if is_singleton? || instance_of?(Module)
|
59
|
+
class_eval do
|
60
|
+
attr_writer name
|
61
|
+
define_method("#{name}_defval") do
|
62
|
+
defval || (instance_eval(&init) if init)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class_eval <<-EOD
|
67
|
+
def #{name}
|
68
|
+
if defined? @#{name} then @#{name}
|
69
|
+
else @#{name} = #{name}_defval
|
70
|
+
end
|
71
|
+
end
|
72
|
+
EOD
|
73
|
+
else
|
74
|
+
class_eval { attr_writer name }
|
75
|
+
define_method(name) do
|
76
|
+
singleton_class.class_eval { attr_reader name }
|
77
|
+
instance_variable_set("@#{name}", defval || (instance_eval(&init) if init))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Object
|
85
|
+
def class_attribute(attr_def, &init)
|
86
|
+
singleton_class.class_eval { attribute(attr_def, &init) }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'utilrb/object/address'
|
2
|
+
if RUBY_VERSION >= "1.9"
|
3
|
+
class Object
|
4
|
+
def has_singleton?; defined? @singleton_class end
|
5
|
+
def singleton_class
|
6
|
+
if defined? @singleton_class
|
7
|
+
return @singleton_class
|
8
|
+
else
|
9
|
+
@singleton_class = class << self
|
10
|
+
class << self
|
11
|
+
alias __ancestors__ ancestors
|
12
|
+
def ancestors; __ancestors__.unshift(self) end
|
13
|
+
end
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
@singleton_class
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
class Object
|
24
|
+
def has_singleton?
|
25
|
+
defined? @singleton_class
|
26
|
+
end
|
27
|
+
def singleton_class
|
28
|
+
if defined? @singleton_class
|
29
|
+
return @singleton_class
|
30
|
+
else
|
31
|
+
klass = class << self; self end
|
32
|
+
instance = self
|
33
|
+
klass.class_eval do
|
34
|
+
@singleton_instance = instance
|
35
|
+
@superclass = instance.class
|
36
|
+
class << self
|
37
|
+
attr_reader :superclass
|
38
|
+
attr_reader :singleton_instance
|
39
|
+
def name
|
40
|
+
"#{@superclass.name}!0x#{@singleton_instance.address.to_s(16)}"
|
41
|
+
end
|
42
|
+
|
43
|
+
alias __ancestors__ ancestors
|
44
|
+
def ancestors; __ancestors__.unshift(self) end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@singleton_class = klass
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'utilrb/gc/force'
|
2
|
+
|
3
|
+
module ObjectStats
|
4
|
+
# Allocates no object
|
5
|
+
def self.count
|
6
|
+
count = 0
|
7
|
+
ObjectSpace.each_object { |obj| count += 1}
|
8
|
+
|
9
|
+
count
|
10
|
+
end
|
11
|
+
|
12
|
+
# Allocates 1 Hash, which is included in the count
|
13
|
+
def self.count_by_class
|
14
|
+
by_class = Hash.new(0)
|
15
|
+
ObjectSpace.each_object { |obj|
|
16
|
+
by_class[obj.class] += 1
|
17
|
+
by_class
|
18
|
+
}
|
19
|
+
by_class
|
20
|
+
end
|
21
|
+
|
22
|
+
# Profiles the memory allocation in the block
|
23
|
+
# If alive is true, then only non-gcable objects
|
24
|
+
# are returned.
|
25
|
+
def self.profile(alive = false)
|
26
|
+
already_disabled = GC.disable
|
27
|
+
before = count_by_class
|
28
|
+
yield
|
29
|
+
after = count_by_class
|
30
|
+
GC.enable unless already_disabled
|
31
|
+
|
32
|
+
after[Hash] -= 1 # Correction for the call of count_by_class
|
33
|
+
profile = before.
|
34
|
+
merge(after) { |klass, old, new| new - old }.
|
35
|
+
delete_if { |klass, count| count == 0 }
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.stats(filter = nil)
|
39
|
+
total_count = 0
|
40
|
+
output = ""
|
41
|
+
count_by_class.each do |klass, obj_count|
|
42
|
+
total_count += obj_count
|
43
|
+
if !filter || klass.name =~ filter
|
44
|
+
output << klass.name << " " << obj_count.to_s << "\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
(output << "Total object count: #{total_count}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
data/lib/utilrb/time.rb
ADDED