spruz 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ module Spruz
2
+ module HashUnion
3
+ def |(other)
4
+ other = other.to_hash if other.respond_to?(:to_hash)
5
+ other.merge(self)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,36 @@
1
+ require 'thread'
2
+
3
+ module Spruz
4
+ class Limited
5
+ # Create a Limited instance, that runs _maximum_ threads at most.
6
+ def initialize(maximum)
7
+ @mutex = Mutex.new
8
+ @continue = ConditionVariable.new
9
+ @maximum = Integer(maximum)
10
+ raise ArgumentError, "maximum < 1" if @maximum < 1
11
+ @count = 0
12
+ end
13
+
14
+ # The maximum number of worker threads.
15
+ attr_reader :maximum
16
+
17
+ # Execute _maximum_ number of threads in parallel.
18
+ def execute
19
+ @mutex.synchronize do
20
+ loop do
21
+ if @count < @maximum
22
+ @count += 1
23
+ Thread.new do
24
+ yield
25
+ @mutex.synchronize { @count -= 1 }
26
+ @continue.signal
27
+ end
28
+ return
29
+ else
30
+ @continue.wait(@mutex)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,71 @@
1
+ module Spruz
2
+ module Memoize
3
+ class ::Module
4
+ class << self
5
+ # Returns the current memoize cache for all the stored objects and
6
+ # method call results.
7
+ def __memoize_cache__
8
+ @__memoize_cache__ ||= {}
9
+ end
10
+
11
+ # Finalizer to delete the stored result for a garbage collected object.
12
+ def __memoize_cache_delete__
13
+ lambda do |id|
14
+ $DEBUG and warn "Deleted method results for object id='#{id}'"
15
+ __memoize_cache__.delete(id)
16
+ end
17
+ end
18
+ end
19
+
20
+ # Automatically memoize calls of the the methods +method_ids+. The
21
+ # memoized results do NOT ONLY depend on the arguments, but ALSO on the
22
+ # object the method is called on.
23
+ def memoize_method(*method_ids)
24
+ method_ids.each do |method_id|
25
+ orig_method = instance_method(method_id)
26
+ __send__(:define_method, method_id) do |*args|
27
+ unless mc = ::Module.__memoize_cache__[__id__]
28
+ mc = ::Module.__memoize_cache__[__id__] ||= {}
29
+ ObjectSpace.define_finalizer(self, ::Module.__memoize_cache_delete__)
30
+ end
31
+ if mc.key?(args)
32
+ result = mc[args]
33
+ else
34
+ result = mc[args] = orig_method.bind(self).call(*args)
35
+ if $DEBUG
36
+ warn "#{self.class} cached method #{method_id}(#{args.inspect unless args.empty?}) = #{result.inspect} [#{__id__}]"
37
+ end
38
+ end
39
+ result
40
+ end
41
+ end
42
+ end
43
+
44
+ # Returns the current memoize cache for this Module.
45
+ def __memoize_cache__
46
+ @__memoize_cache__
47
+ end
48
+
49
+ # Automatically memoize calls of the functions +function_ids+. The
50
+ # memoized result does ONLY depend on the arguments given to the
51
+ # function.
52
+ def memoize_function(*function_ids)
53
+ mc = @__memoize_cache__ ||= {}
54
+ function_ids.each do |method_id|
55
+ orig_method = instance_method(method_id)
56
+ __send__(:define_method, method_id) do |*args|
57
+ if mc.key?(args)
58
+ result = mc[args]
59
+ else
60
+ result = mc[args] = orig_method.bind(self).call(*args)
61
+ if $DEBUG
62
+ warn "#{self.class} cached function #{method_id}(#{args.inspect unless args.empty?}) = #{result.inspect}"
63
+ end
64
+ end
65
+ result
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,53 @@
1
+ module Spruz
2
+ # This module can be mixed into all classes, whose instances respond to the
3
+ # [] and size-methods, like for example Array. The returned elements from []
4
+ # should respond to the succ method.
5
+ module Minimize
6
+ # Returns a minimized version of this object, that is successive elements
7
+ # are substituted with ranges a..b. In the situation ..., x, y,... and y !=
8
+ # x.succ a range x..x is created, to make it easier to iterate over all the
9
+ # ranges in one run. A small example:
10
+ # [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ].minimize # => [ 'A'..'C', 'G'..'G', 'K'..'M' ]
11
+ #
12
+ # If the order of the original elements doesn't matter, it's a good idea to
13
+ # first sort them and then minimize:
14
+ # [ 5, 1, 4, 2 ].sort.minimize # => [ 1..2, 4..5 ]
15
+ def minimize
16
+ result = []
17
+ last_index = size - 1
18
+ size.times do |i|
19
+ result << [ self[0] ] if i == 0
20
+ if self[i].succ != self[i + 1] or i == last_index
21
+ result[-1] << self[i]
22
+ result << [ self[i + 1] ] unless i == last_index
23
+ end
24
+ end
25
+ result.map! { |a, b| a..b }
26
+ end
27
+
28
+ # First minimizes this object, then calls the replace method with the
29
+ # result.
30
+ def minimize!
31
+ replace minimize
32
+ end
33
+
34
+ # Invert a minimized version of an object. Some small examples:
35
+ # [ 'A'..'C', 'G'..'G', 'K'..'M' ].unminimize # => [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ]
36
+ # and
37
+ # [ 1..2, 4..5 ].unminimize # => [ 1, 2, 4, 5 ]
38
+ def unminimize
39
+ result = []
40
+ for range in self
41
+ for e in range
42
+ result << e
43
+ end
44
+ end
45
+ result
46
+ end
47
+
48
+ # Invert a minimized version of this object in place.
49
+ def unminimize!
50
+ replace unminimize
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,11 @@
1
+ module Spruz
2
+ module ModuleGroup
3
+ def self.[](*modules)
4
+ modul = Module.new
5
+ modules.each do |m|
6
+ m.module_eval { include modul }
7
+ end
8
+ modul
9
+ end
10
+ end
11
+ end
data/lib/spruz/null.rb ADDED
@@ -0,0 +1,20 @@
1
+ module Spruz
2
+ # Implementation of the null object pattern in Ruby.
3
+ module Null
4
+ def method_missing(*)
5
+ self
6
+ end
7
+
8
+ def to_s
9
+ ''
10
+ end
11
+
12
+ def inspect
13
+ 'NULL'
14
+ end
15
+ end
16
+
17
+ NULL = Class.new do
18
+ include Spruz::Null
19
+ end.new
20
+ end
data/lib/spruz/once.rb ADDED
@@ -0,0 +1,23 @@
1
+ module Spruz
2
+ module Once
3
+ include File::Constants
4
+
5
+ module_function
6
+
7
+ def only_once(lock_filename = nil, locking_constant = nil)
8
+ lock_filename ||= $0
9
+ locking_constant ||= LOCK_EX
10
+ f = File.new(lock_filename, RDONLY)
11
+ f.flock(locking_constant) and yield
12
+ ensure
13
+ if f
14
+ f.flock LOCK_UN
15
+ f.close
16
+ end
17
+ end
18
+
19
+ def try_only_once(lock_filename = nil, locking_constant = nil, &block)
20
+ only_once(lock_filename, locking_constant || LOCK_EX | LOCK_NB, &block)
21
+ end
22
+ end
23
+ end
data/lib/spruz/p.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'pp'
2
+
3
+ module Spruz
4
+ module P
5
+ private
6
+
7
+ # Raise a runtime error with the inspected objects +objs+ (obtained by
8
+ # calling the #inspect method) as their message text. This is useful for
9
+ # quick debugging.
10
+ def p!(*objs)
11
+ raise((objs.size < 2 ? objs.first : objs).inspect)
12
+ end
13
+
14
+ # Raise a runtime error with the inspected objects +objs+ (obtained by
15
+ # calling the #pretty_inspect method) as their message text. This is useful
16
+ # for quick debugging.
17
+ def pp!(*objs)
18
+ raise("\n" + (objs.size < 2 ? objs.first : objs).pretty_inspect.chomp)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module Spruz
2
+ module PartialApplication
3
+ # If this module is included into a Proc (or similar object), it tampers
4
+ # with its Proc#arity method.
5
+ def self.included(modul)
6
+ modul.module_eval do
7
+ old_arity = instance_method(:arity)
8
+ define_method(:arity) do
9
+ @__arity__ or old_arity.bind(self).call
10
+ end
11
+ end
12
+ super
13
+ end
14
+
15
+ # Create a partial application of this Proc (or similar object) using
16
+ # _args_ as the already applied arguments.
17
+ def partial(*args)
18
+ if args.empty?
19
+ dup
20
+ elsif args.size > arity
21
+ raise ArgumentError, "wrong number of arguments (#{args.size} for #{arity})"
22
+ else
23
+ f = lambda { |*b| call(*(args + b)) }
24
+ f.instance_variable_set :@__arity__, arity - args.size
25
+ f
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ module Spruz
2
+ # A bit more versatile rounding for Ruby
3
+ module Round
4
+ def self.included(klass)
5
+ if klass.instance_method(:round)
6
+ klass.class_eval do
7
+ begin
8
+ remove_method :round
9
+ rescue NameError
10
+ end
11
+ end
12
+ super
13
+ else
14
+ raise NoMethodError, 'no round method found'
15
+ end
16
+ end
17
+
18
+ def round(places = 0)
19
+ unless Integer === places
20
+ raise TypeError, "argument places has to be an Integer"
21
+ end
22
+ if places < 0
23
+ max_places = -Math.log(self.abs + 1) / Math.log(10)
24
+ raise ArgumentError, "places has to be >= #{max_places.ceil}" if max_places > places
25
+ end
26
+ t = self
27
+ f = 10.0 ** places
28
+ t *= f
29
+ if t >= 0.0
30
+ t = (t + 0.5).floor
31
+ elsif t < 0.0
32
+ t = (t - 0.5).ceil
33
+ end
34
+ t /= f
35
+ t.nan? ? self : t
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ module Spruz
2
+ module Shuffle
3
+ def shuffle!
4
+ (size - 1) .downto(1) do |i|
5
+ j = rand(i + 1)
6
+ self[i], self[j] = self[j], self[i]
7
+ end
8
+ self
9
+ end
10
+
11
+ def shuffle
12
+ dup.shuffle!
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ module Spruz
2
+ module Subhash
3
+ # Create a subhash from this hash, that only contains key-value pairs
4
+ # matching +patterns+ and return it. +patterns+ can be for example /^foo/
5
+ # to put 'foobar' and 'foobaz' or 'foo'/:foo to put 'foo' into the subhash.
6
+ #
7
+ # If a block is given this method yields to it after the first pattern
8
+ # matched with a 3-tuple of +(key, value, match_data)+ using the return
9
+ # value of the block as the value of the result hash. +match_data+ is a
10
+ # MatchData instance if the matching pattern was a regular rexpression
11
+ # otherwise it is nil.
12
+ def subhash(*patterns)
13
+ patterns.map! { |pat| pat.respond_to?(:match) ? pat : pat.to_s }
14
+ result =
15
+ if default_proc
16
+ self.class.new(&default_proc)
17
+ else
18
+ self.class.new(default)
19
+ end
20
+ if block_given?
21
+ each do |k, v|
22
+ patterns.each { |pat|
23
+ if pat === k.to_s
24
+ result[k] = yield(k, v, $~)
25
+ break
26
+ end
27
+ }
28
+ end
29
+ else
30
+ each do |k, v|
31
+ result[k] = v if patterns.any? { |pat| pat === k.to_s }
32
+ end
33
+ end
34
+ result
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Spruz
2
+ module TimeDummy
3
+ def self.included(modul)
4
+ modul.module_eval do
5
+ class << self
6
+ alias really_new new
7
+ end
8
+
9
+ extend ClassMethods
10
+
11
+ class << self
12
+ alias now new
13
+ end
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ attr_accessor :dummy
19
+
20
+ def new
21
+ if dummy
22
+ dummy.dup
23
+ else
24
+ really_new
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ module Spruz
2
+ module ToProc
3
+ def to_proc
4
+ lambda do |obj, *args|
5
+ obj.__send__(self, *args[0..-1])
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Spruz
2
+ module UniqBy
3
+ def uniq_by(&b)
4
+ b ||= lambda { |x| x }
5
+ inject({}) { |h, e| h[b[e]] ||= e; h }.values
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Spruz
2
+ # Spruz version
3
+ VERSION = '0.1.0'
4
+ VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
7
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
8
+ end