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.
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
+