Add bin and edit workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
@@ -0,0 +1,46 @@
= Cloneable
Require the library.
require 'facets/cloneable'
We'll use this dummy class.
class Foo
include Cloneable
def initialize
@bar=[]
end
def bar_id
@bar.object_id
end
end
Try #dup.
a = Foo.new
b = a.dup
b.bar_id.refute == a.bar_id
a.taint
b = a.dup
b.assert.tainted?
a.freeze
b = a.dup
b.refute.frozen?
Note try #clone.
a = Foo.new
b = a.clone
b.bar_id.refute == a.bar_id
a.taint
b = a.dup
b.assert.tainted?
a.freeze
b = a.clone
b.assert.frozen?
@@ -0,0 +1,75 @@
= Enumerable::Arguments
Require the library.
require 'facets/enumargs'
This will serve as our example class.
class PlusArray
include Enumerable::Arguments
def initialize(arr)
@arr = arr
end
def each(n=0)
@arr.each{ |e| yield(e+n) }
end
end
Now Enumerable methods such as #map and #collect
take an argument as well.
t = PlusArray.new([1,2,3])
t.collect(4){ |e| e }.assert == [5,6,7]
Filtering methods such as #select and reject work
as well.
t = PlusArray.new([1,2,3])
t.select(4){ |x| x == 6 }.assert == [6]
t = PlusArray.new([1,2,3])
t.reject(4){ |x| x == 6 }.assert == [5,7]
We can covert to an array using #to_a with an argument.
t = PlusArray.new([1,2,3])
t.to_a(4).assert == [5,6,7]
We can get the minimum value using #min.
t = PlusArray.new([1,2,3])
t.min(4).assert == 5
And get the maximum value using #min.
t = PlusArray.new([1,2,3])
t.max(4).assert == 7
Methods that already take and argument, now take two
such as #include?
t = PlusArray.new([1,2,3])
t.assert.include?(7,4)
And #each_slice.
t = PlusArray.new([1,2,3,4])
a = []
t.each_slice(2,4){ |e,f| a << [e,f] }
a.assert == [[5,6],[7,8]]
The #find method has a slightly different interface
than the original Enumerable.
t = PlusArray.new([1,2,3,4])
f = t.find(2, :ifnone=>lambda{:NOPE}) { |a| a == 10 }
f.assert == :NOPE
The #grep method should also work.
t = PlusArray.new(['a1','b2','a3','b4'])
t.grep(/^b/, 'x').assert == ['b2x','b4x']
@@ -0,0 +1,35 @@
= Equitqable
Require the library.
require 'facets/equitable'
We will use this simple class as an example.
class C
include Equitable(:a,:b)
attr_accessor :a, :b
def initialize(a,b)
@a = a
@b = b
end
end
Now, if two instance of our sample class +C+ have
equal attributes +@a+ and +@b+ then they will
be equal.
c1 = C.new(10,20)
c2 = C.new(10,20)
c2.assert == c1
Otherwise they will not be equal.
c1 = C.new(10, 10)
c2 = C.new(10, 20)
c2.refute == c1
@@ -0,0 +1,42 @@
= Instantiable
Require the library.
require 'facets/instantiable'
We will use this module as an example.
module M
include Instantiable
attr :a
def initialize(a)
@a = a
end
end
As we can see M is now fully instantiable, as any
class would be.
m = M.new(1)
m.a.assert == 1
We can also use #extend rather than #include and
get the same result.
module N
extend Instantiable
attr :a
def initialize( a )
@a = a
end
end
As we saw with +M+ so too with +N+.
n = N.new( 1 )
n.a.assert == 1
@@ -0,0 +1,22 @@
== BasicObject
require 'facets/basicobject'
o = Class.new(BasicObject).new
Should ignore new kernel methods.
Kernel.module_eval { def xxx ; end }
expect NoMethodError do
o.xxx
end
Should ignore new object methods.
Object.class_eval { def yyy ; end }
expect NoMethodError do
o.yyy
end
@@ -0,0 +1,134 @@
= Memoizable
Memoizable allows
require 'facets/memoizable'
The classic example is calculating the Fibonacci sequence.
class Fibonacci
include Memoizable
def fib( num )
return num if num < 2
fib(num - 1) + fib(num - 2)
end
memoize :fib
end
The first time will take a moment to calculate.
f = Fibonacci.new
f.fib(100)
The second time will be returned almost instantly.
f = Fibonacci.new
f.fib(100)
The following example makes if very clear what memoize is doing.
class MemoExample
include Memoizable
attr_accessor :a
memoize :a
end
m = MemoExample.new
m.a = 10
m.a #=> 10
m.a = 20
m.a #=> 10
Even though @a is assigned to 20, the method #a continues to return 10.
Memoizable is designed to handle a number of typically problematic aspects
of memoization implementations. First a memoizable object can be frozen.
f = Fibonacci.new
f.freeze
f.fib(100)
Memoizable objects are freezable because it does not use an instance variable
to store the memoized return values. Instead it uses a global class instance
variable in +Memoizable.cache+.
However, this also means the memoization cache is not preserved when an object
is duplicated. If this behavior is desired an aditional module is provided
called `Memoizable::Copy`. When the `Memoiazble::Copy` module is included into
a class it not only adds the #memoize class methods but also includes
an #initialize_copy method, which copies the appropriate cache entries when
#dup or #clone is used. Keep this in mind. It is important to call #super if you
override the #initialize_copy method in a class that uses `Memoizable::Copy`.
class MemoExample2
include Memoizable::Copy
attr_accessor :a
memoize :a
end
m = MemoExample2.new
m.a = 10
m.a #=> 10
n = m.dup
n.a = 20
n.a #=> 10
The `#memoize` method also accepts a few options that can be used to modify
the behvior of the memoizaiton. To memoize a method across all objects
of the same class and not just per-object, set the `:class` option to true.
class MemoExample3
include Memoizable
attr_accessor :a
memoize :a, :class=>true
end
m = MemoExample3.new
m.a = 10
m.a #=> 10
n = MemoExample3.new
n.a #=> 10
Memoization is indexed based on arguments passed to the method, as can be seen
in the Fibonacci example. Methods can also be memoized by name only, forgoing
any indexing based on arguments passed. To do this, set the `:arguments`
option to +false+.
class MemoExample4
include Memoizable
def f(n)
n + n
end
memoize :f, :arguments=>false
end
m = MemoExample4.new
m.f(1)
m.f(2) #=> 2
m.f(3) #=> 2
Blocks passed to a method normally have only a present vs. non-present effect
on the memoization index. In other words the return value of a method will be
cached under one key if a block is passed to it and under a different index
if not. It doesn't matter if blocks passed in actually differ, since
the only way to compare blocks is by their +object_id+ and it is very rare
for the exact same block object to be reused.
Finally, the `:freeze` option can be used to freeze the memoized results.
class MemoExample5
include Memoizable
def f(n)
(n + n).to_s
end
memoize :f, :freeze=>true
end
m = MemoExample5.new
m.f(1).frozen? #=> true
m.f(2).frozen? #=> true
@@ -0,0 +1,156 @@
= Multiton
The Multion pattern is essentially the same as the Singleton pattern, but
unlike it's fully unique brethren Multiton's are identical if their
initialization parameters are identical.
To demontrate we first need to load the Facets multiton.rb script.
require 'facets/multiton'
Now for the various exmples.
== EXAMPLE A - STANDARD USAGE
class SomeMultitonClass
include Multiton
attr :arg
def initialize(arg)
@arg = arg
end
end
a = SomeMultitonClass.instance(4)
b = SomeMultitonClass.instance(4) # a and b are same object
c = SomeMultitonClass.instance(2) # c is a different object
a.assert == b
x = [a.arg, b.arg].max * 10 + c.arg
x.assert == 42
== EXAMPLE B - MODIFY AN EXISTING CLASS
We can modify an existing class (if we are so bold), for example we can
add shared filehandles to the File class.
class ::File
include Multiton
end
lineno = __LINE__
# HERE1
# HERE2
a = File.instance(__FILE__)
b = File.instance(__FILE__)
b.assert == a
lineno.times{ a.gets }
a.gets.strip.assert == "# HERE1"
b.gets.strip.assert == "# HERE2"
== EXAMPLE C - INHERITENCE
class A < String
include Multiton
end
# B is also a multiton - with it's OWN object cache
class B < A; end
# w is the same object as x, y is the same object as z
w,x,y,z = A.instance('A'), A.instance('A'), B.instance('B'), B.instance('B')
x.object_id.assert == w.object_id
z.object_id.assert == y.object_id
a = B.instance('A')
b = B.instance('A')
w.object_id.refute == a.object_id # (each class has it's own pool)
b.object_id.assert == a.object_id
== EXAMPLE D - MULTIPLE MODULE INCLUSION (does nothing)
class A < String
include Multiton
end
# B is also a multiton - with it's OWN object cache
class B < A; end
# w is the same object as x, y is the same object as z
w,x,y,z = A.instance('A'), A.instance('A'), B.instance('B'), B.instance('B')
yz_id = y.object_id || z.object_id
If we include Multiton again, it will have to effect.
B.class_eval {
include Multiton
}
# y is not only the same object as z, but they are both the same object(s)
# as from EXAMPLE C
y,z = B.instance('B'), B.instance('B')
yz_id.assert == y.object_id
yz_id.assert == z.object_id
== EXAMPLE E - SO YOU WANNA USE NEW INSTEAD OF INSTANCE
module K
# use an inner class which is itself a multiton
class K < String; include Multiton; end
# define a new which returns a mutltion using #instance...
class << self
def new(*args, &block)
K.instance(*args, &block)
end
end
end
the = K.new '4'
answer = K.new '2'
x = sprintf( "%s%s", the, answer )
x.assert == "42"
the.class.assert == K::K
== EXAMPLE F - using Klass.multiton_id
class Klass
include Multiton
def initialize( important, not_important )
@important, @not_important = important, not_important
end
def Klass.multiton_id(*args, &block)
# we consider only the first arg
important, not_important = *args
important
end
end
a = Klass.instance( :a, :b )
b = Klass.instance( :a, :c )
c = Klass.instance( :b, :b )
a.assert == b
c.refute == a
c.refute == b