utilrb 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
data/lib/utilrb.rb
ADDED
data/lib/utilrb/array.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Utilrb
|
2
|
+
VERSION = "0.2" unless defined? Utilrb::VERSION
|
3
|
+
|
4
|
+
unless defined? UTILRB_FASTER_MODE
|
5
|
+
if ENV['UTILRB_FASTER_MODE'] == 'no'
|
6
|
+
UTILRB_FASTER_MODE = nil
|
7
|
+
STDERR.puts "Utilrb: not loading the C extension"
|
8
|
+
else
|
9
|
+
begin
|
10
|
+
require 'utilrb/faster'
|
11
|
+
UTILRB_FASTER_MODE = true
|
12
|
+
STDERR.puts "Utilrb: loaded C extension" if ENV['UTILRB_FASTER_MODE']
|
13
|
+
rescue LoadError => e
|
14
|
+
raise unless e.message =~ /no such file to load/
|
15
|
+
if ENV['UTILRB_FASTER_MODE'] == 'yes'
|
16
|
+
raise LoadError, "unable to load Util.rb C extension: #{e.message}"
|
17
|
+
else
|
18
|
+
UTILRB_FASTER_MODE = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Yields if the faster extension is not present
|
25
|
+
# This is used by Utilrb libraries to provide a
|
26
|
+
# Ruby version if the C extension is not loaded
|
27
|
+
def self.unless_faster # :yield:
|
28
|
+
unless UTILRB_FASTER_MODE
|
29
|
+
return yield if block_given?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Yields if the faster extension is present. This is used for Ruby code
|
34
|
+
# which depends on methods in the C extension
|
35
|
+
def self.if_faster(&block)
|
36
|
+
require_faster(nil, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Yields if the faster extension is present, and
|
40
|
+
# issue a warning otherwise. This is used for Ruby
|
41
|
+
# code which depends on methods in the C extension
|
42
|
+
def self.require_faster(name)
|
43
|
+
if UTILRB_FASTER_MODE
|
44
|
+
yield if block_given?
|
45
|
+
elsif name
|
46
|
+
STDERR.puts "Utilrb: not loading #{name} since the C extension is not available"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# A null enumerator which can be used to seed sequence enumeration. See
|
2
|
+
# Kernel#null_enum
|
3
|
+
class NullEnumerator
|
4
|
+
def each; self end
|
5
|
+
include Enumerable
|
6
|
+
end
|
7
|
+
|
8
|
+
module Kernel
|
9
|
+
# returns always the same null enumerator, to avoid creating objects.
|
10
|
+
# It can be used as a seed to #inject:
|
11
|
+
#
|
12
|
+
# enumerators.inject(null_enum) { |a, b| a + b }.each do |element|
|
13
|
+
# end
|
14
|
+
def null_enum
|
15
|
+
@@null_enumerator ||= NullEnumerator.new.freeze
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Enumerable
|
2
|
+
def random_element
|
3
|
+
if Array === self
|
4
|
+
self[rand(size)]
|
5
|
+
elsif respond_to?(:to_ary)
|
6
|
+
to_ary.random_element
|
7
|
+
elsif respond_to?(:size)
|
8
|
+
element = rand(size)
|
9
|
+
each_with_index { |e, i| return e if i == element }
|
10
|
+
nil
|
11
|
+
elsif respond_to?(:to_a)
|
12
|
+
to_a.random_element
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# An enumerator which iterates on a sequence of enumerator
|
2
|
+
class SequenceEnumerator
|
3
|
+
def initialize; @sequence = Array.new end
|
4
|
+
# Adds +object+ at the back of the sequence
|
5
|
+
def <<(object); @sequence << object; self end
|
6
|
+
alias :+ :<<
|
7
|
+
|
8
|
+
def each
|
9
|
+
@sequence.each { |enum| enum.each { |o| yield(o) } } if block_given?
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
include Enumerable
|
14
|
+
end
|
15
|
+
|
16
|
+
module Enumerable # :nodoc
|
17
|
+
# Builds a sequence of enumeration object.
|
18
|
+
# ([1, 2].enum_for + [2, 3]).each => 1, 2, 2, 3
|
19
|
+
def +(other_enumerator) # :nodoc
|
20
|
+
SequenceEnumerator.new << self << other_enumerator
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'utilrb/common'
|
2
|
+
require 'enumerator'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
# Enumerator object which removes duplicate entries. See
|
6
|
+
# Kernel#each_uniq
|
7
|
+
class UniqEnumerator < Enumerable::Enumerator
|
8
|
+
def initialize(root, enum_with, args, key = nil)
|
9
|
+
super(root, enum_with, *args)
|
10
|
+
@key = key
|
11
|
+
@result = Hash.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
if block_given?
|
16
|
+
@result.clear
|
17
|
+
result = @result
|
18
|
+
super() do |v|
|
19
|
+
k = @key ? @key.call(v) : v
|
20
|
+
|
21
|
+
if !result.has_key?(k)
|
22
|
+
result[k] = v
|
23
|
+
yield(v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
result.values
|
28
|
+
else
|
29
|
+
self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
include Enumerable
|
34
|
+
end
|
35
|
+
|
36
|
+
class Object
|
37
|
+
# Enumerate removing the duplicate entries
|
38
|
+
def enum_uniq(enum_with = :each, *args, &filter)
|
39
|
+
UniqEnumerator.new(self, enum_with, args, filter)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Utilrb.unless_faster do
|
44
|
+
module Enumerable
|
45
|
+
# call-seq:
|
46
|
+
# enum.each_uniq { |obj| ... }
|
47
|
+
#
|
48
|
+
# Yields all unique values found in +enum+
|
49
|
+
#
|
50
|
+
def each_uniq(&iterator)
|
51
|
+
seen = Set.new
|
52
|
+
each do |obj|
|
53
|
+
if !seen.include?(obj)
|
54
|
+
seen << obj
|
55
|
+
yield(obj)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
data/lib/utilrb/gc.rb
ADDED
data/lib/utilrb/hash.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Kernel
|
2
|
+
# Raises if +object+ can accept calls with exactly +arity+ arguments.
|
3
|
+
# object should respond to #arity
|
4
|
+
def check_arity(object, arity)
|
5
|
+
unless object.arity == arity || (object.arity < 0 && object.arity > - arity - 2)
|
6
|
+
raise ArgumentError, "#{object} does not accept to be called with #{arity} argument(s)", caller(2)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'utilrb/hash/to_sym_keys'
|
2
|
+
require 'utilrb/hash/slice'
|
3
|
+
module Kernel
|
4
|
+
# Partitions an option hash between known arguments and unknown
|
5
|
+
# arguments, with default value support. All option keys are
|
6
|
+
# converted to symbols for consistency.
|
7
|
+
#
|
8
|
+
# call-seq:
|
9
|
+
# filter_options(option, hash) -> known, unknown
|
10
|
+
# filter_options(option, array) -> known, unknown
|
11
|
+
# filter_options(nil, known_options) -> default_options, {}
|
12
|
+
#
|
13
|
+
def filter_options(options, option_spec)
|
14
|
+
options = (options || Hash.new).to_sym_keys
|
15
|
+
# cannot use #to_sym_keys as option_spec can be an array
|
16
|
+
option_spec = option_spec.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
|
17
|
+
|
18
|
+
unknown_options = options.slice(*(options.keys - option_spec.keys))
|
19
|
+
known_options = options.slice(*option_spec.keys)
|
20
|
+
|
21
|
+
# Set default values defined in the spec
|
22
|
+
option_spec.each_key do |k|
|
23
|
+
value = option_spec[k]
|
24
|
+
if !known_options.has_key?(k) && !value.nil?
|
25
|
+
known_options[k] ||= value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
return *[known_options, unknown_options]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Validates an option hash, with default value support. See #filter_options
|
33
|
+
#
|
34
|
+
# In the first form, +option_hash+ should contain keys which are also
|
35
|
+
# in known_hash. The non-nil values of +known_hash+ are used as default
|
36
|
+
# values. In the second form, +known_array+ is an array of option
|
37
|
+
# keys. +option_hash+ keys shall be in +known_array+. +nil+ is treated
|
38
|
+
# as an empty option hash, all keys are converted into symbols.
|
39
|
+
#
|
40
|
+
def validate_options(options, known_options)
|
41
|
+
opt, unknown = filter_options(options, known_options)
|
42
|
+
unless unknown.empty?
|
43
|
+
not_valid = unknown.keys.map { |m| "'#{m}'" }.join(" ")
|
44
|
+
raise ArgumentError, "unknown options #{not_valid}", caller(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
opt
|
48
|
+
end
|
49
|
+
|
50
|
+
# call-seq:
|
51
|
+
# validate_option(options, name, required, message) { |v| ... }
|
52
|
+
# validate_option(options, name, required, message)
|
53
|
+
#
|
54
|
+
# Validates option +name+ in the +options+ hash. If required is true,
|
55
|
+
# raises ArgumentError if the option is not present. Otherwise, yields
|
56
|
+
# its value to an optional block, which should return if the value is
|
57
|
+
# valid, or false otherwise. If the value is invalid, raises ArgumentError
|
58
|
+
# with +message+ or a standard message.
|
59
|
+
def validate_option(options, name, required, message = nil)
|
60
|
+
if required && !options.has_key?(name)
|
61
|
+
raise ArgumentError, "missing required option #{name}"
|
62
|
+
elsif options.has_key?(name) && block_given?
|
63
|
+
if !yield(options[name])
|
64
|
+
raise ArgumentError, (message || "invalid option value #{options[name]} for #{name}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kernel
|
2
|
+
# Yields every +cycle+ seconds
|
3
|
+
def poll(cycle)
|
4
|
+
loop do
|
5
|
+
yield
|
6
|
+
sleep(cycle)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
# Yields every +cycle+ seconds until
|
10
|
+
# the block returns true.
|
11
|
+
def wait_until(cycle)
|
12
|
+
until yield
|
13
|
+
sleep(cycle)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
# Yields every +cycle+ seconds until
|
17
|
+
# the block returns false.
|
18
|
+
def wait_while(cycle)
|
19
|
+
while yield
|
20
|
+
sleep(cycle)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Logger
|
2
|
+
# Forward logger output methods to the logger attribute, so that
|
3
|
+
# we can do
|
4
|
+
# MyModule.debug "debug_info"
|
5
|
+
# instead of
|
6
|
+
# MyModule.logger.debug "debug_info"
|
7
|
+
module Forward
|
8
|
+
[ :debug, :info, :warn, :error, :fatal, :unknown ].each do |level|
|
9
|
+
class_eval <<-EOF
|
10
|
+
def #{level}(*args, &proc); logger.#{level}(*args, &proc) end
|
11
|
+
EOF
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'facet/module/dirname'
|
2
|
+
require 'facet/kernel/constant'
|
3
|
+
class Logger
|
4
|
+
# Define a hierarchy of loggers mapped to the module hierarchy.
|
5
|
+
# It defines the #logger accessor which either returns the logger
|
6
|
+
# attribute of the module, if one is defined, or its parent logger
|
7
|
+
# attribute.
|
8
|
+
#
|
9
|
+
# module First
|
10
|
+
# include Hierarchy
|
11
|
+
# self.logger = Logger.new
|
12
|
+
#
|
13
|
+
# module Second
|
14
|
+
# include Hierarchy
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Second.logger will return First.logger. If we do
|
19
|
+
# Second.logger = Logger.new, then this one would
|
20
|
+
# be returned.
|
21
|
+
module Hierarchy
|
22
|
+
attr_writer :logger
|
23
|
+
def logger
|
24
|
+
return @logger if defined?(@logger) && @logger
|
25
|
+
if kind_of?(Module)
|
26
|
+
constant(self.dirname).logger
|
27
|
+
else
|
28
|
+
self.class.logger
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|