utilrb 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/Changes.txt +20 -0
  2. data/License.txt +26 -0
  3. data/Manifest.txt +64 -0
  4. data/README.txt +44 -0
  5. data/Rakefile +46 -0
  6. data/bm/allocation.rb +7 -0
  7. data/bm/speed.rb +19 -0
  8. data/ext/extconf.rb +5 -0
  9. data/ext/faster.cc +48 -0
  10. data/ext/swap.cc +61 -0
  11. data/ext/value_set.cc +290 -0
  12. data/lib/utilrb.rb +2 -0
  13. data/lib/utilrb/array.rb +2 -0
  14. data/lib/utilrb/array/to_s.rb +16 -0
  15. data/lib/utilrb/common.rb +50 -0
  16. data/lib/utilrb/enumerable.rb +2 -0
  17. data/lib/utilrb/enumerable/null.rb +18 -0
  18. data/lib/utilrb/enumerable/random_element.rb +16 -0
  19. data/lib/utilrb/enumerable/sequence.rb +24 -0
  20. data/lib/utilrb/enumerable/uniq.rb +61 -0
  21. data/lib/utilrb/exception.rb +2 -0
  22. data/lib/utilrb/exception/full_message.rb +8 -0
  23. data/lib/utilrb/gc.rb +2 -0
  24. data/lib/utilrb/gc/force.rb +11 -0
  25. data/lib/utilrb/hash.rb +2 -0
  26. data/lib/utilrb/hash/slice.rb +6 -0
  27. data/lib/utilrb/hash/to_s.rb +6 -0
  28. data/lib/utilrb/hash/to_sym_keys.rb +6 -0
  29. data/lib/utilrb/kernel.rb +2 -0
  30. data/lib/utilrb/kernel/arity.rb +10 -0
  31. data/lib/utilrb/kernel/options.rb +69 -0
  32. data/lib/utilrb/kernel/poll.rb +24 -0
  33. data/lib/utilrb/kernel/require.rb +12 -0
  34. data/lib/utilrb/kernel/swap.rb +2 -0
  35. data/lib/utilrb/logger.rb +3 -0
  36. data/lib/utilrb/logger/forward.rb +15 -0
  37. data/lib/utilrb/logger/hierarchy.rb +34 -0
  38. data/lib/utilrb/module.rb +2 -0
  39. data/lib/utilrb/module/ancestor_p.rb +6 -0
  40. data/lib/utilrb/module/attr_enumerable.rb +28 -0
  41. data/lib/utilrb/module/define_method.rb +30 -0
  42. data/lib/utilrb/module/include.rb +30 -0
  43. data/lib/utilrb/module/inherited_enumerable.rb +122 -0
  44. data/lib/utilrb/object.rb +2 -0
  45. data/lib/utilrb/object/address.rb +14 -0
  46. data/lib/utilrb/object/attribute.rb +89 -0
  47. data/lib/utilrb/object/singleton_class.rb +53 -0
  48. data/lib/utilrb/objectstats.rb +52 -0
  49. data/lib/utilrb/time.rb +2 -0
  50. data/lib/utilrb/time/to_hms.rb +6 -0
  51. data/lib/utilrb/unbound_method.rb +2 -0
  52. data/lib/utilrb/unbound_method/call.rb +5 -0
  53. data/lib/utilrb/value_set.rb +17 -0
  54. data/test/test_array.rb +9 -0
  55. data/test/test_config.rb +4 -0
  56. data/test/test_enumerable.rb +89 -0
  57. data/test/test_gc.rb +39 -0
  58. data/test/test_hash.rb +22 -0
  59. data/test/test_kernel.rb +70 -0
  60. data/test/test_misc.rb +42 -0
  61. data/test/test_module.rb +127 -0
  62. data/test/test_object.rb +65 -0
  63. data/test/test_objectstats.rb +19 -0
  64. data/test/test_unbound_method.rb +23 -0
  65. metadata +128 -0
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -0,0 +1,16 @@
1
+ class Array
2
+ def to_s
3
+ stack = (Thread.current[:array_to_s] ||= [])
4
+ if stack.include?(self)
5
+ "..."
6
+ else
7
+ begin
8
+ stack.push self
9
+ map { |obj| obj.to_s }.join(", ")
10
+ ensure
11
+ stack.pop
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -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,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -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
+
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -0,0 +1,8 @@
1
+
2
+ class Exception
3
+ def full_message
4
+ first, *remaining = backtrace
5
+ "#{first}: #{message} (#{self.class})\n\tfrom " + remaining.join("\n\tfrom ")
6
+ end
7
+ end
8
+
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -0,0 +1,11 @@
1
+ module GC
2
+ # Forcefully starts the GC even when GC.disable has been called
3
+ def self.force
4
+ already_enabled = !GC.enable
5
+ GC.start
6
+ ensure
7
+ GC.disable unless already_enabled
8
+ end
9
+ end
10
+
11
+
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -0,0 +1,6 @@
1
+ class Hash
2
+ def slice(*keys)
3
+ keys.inject({}) { |h, k| h[k] = self[k] if has_key?(k); h }
4
+ end
5
+ end
6
+
@@ -0,0 +1,6 @@
1
+ class Hash
2
+ def to_s
3
+ map { |k, v| "#{k} => #{v}" }.join(", ")
4
+ end
5
+ end
6
+
@@ -0,0 +1,6 @@
1
+ class Hash
2
+ def to_sym_keys
3
+ inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
4
+ end
5
+ end
6
+
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -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,12 @@
1
+ module Kernel
2
+ # Require all .rb files in the +filename+ directory
3
+ def require_dir(filename)
4
+ dirname = filename.gsub(/.rb$/, '')
5
+ Dir.new(dirname).each do |file|
6
+ if file =~ /\.rb$/
7
+ require File.join(dirname, file)
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,2 @@
1
+ require 'utilrb/common'
2
+ Utilrb.require_faster('Kernel#swap!')
@@ -0,0 +1,3 @@
1
+ require 'logger'
2
+ require 'utilrb/kernel/require'
3
+ require_dir(__FILE__)
@@ -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
+