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,6 @@
= Hashery
For the following demos the `hashery` script has
been preloaded and the Hashery namespace has been
included into the demo context for convenience.
@@ -0,0 +1,63 @@
= OpenHash
An OpenHash is a Hash that provides +open+ access to its entries via method
calls. Writers (methods ending in =-marks) assign entries. Methods without
special puncuation will retrieve entries.
o = OpenHash.new
o.a = 1
o.b = 2
o.a.assert == 1
o.b.assert == 2
Writers always use a Symbol for keys in the underlying Hash.
o.to_h.assert == { :a=>1, :b=>2 }
All the usual Hash methods are still available in an OpenHash.
c = o.map{ |k,v| [k,v] }
c.assert.include?([:a,1])
c.assert.include?([:b,2])
And they are protected from being overridden by writers.
o.map = 3
o.map.refute == 3
Even so, the underlying Hash object does contain the entry even
when it cannot be accessed via a reader method.
o.to_h.assert == { :a=>1, :b=>2, :map=>3 }
We can see if a method is open or not via the `#open?` method.
o.open?(:a).assert == true
o.open?(:map).assert == false
For some usecases it may be necessary to give up access to one or
more Hash methods in favor of access to the hash entries. This can
be done using the `#open!` method.
o.open!(:map, :merge)
o.map.assert == 3
o.merge = 4
o.merge.assert == 4
Becuase of nature of a writer, a certain set of Hash methods are always
protected, in particluar all methods buffered by underscore (e.g. `__id__`).
So these cannot be opened.
expect ArgumentError do
o.open!(:__id__)
end
Even though writers alwasy use Symbols as keys, because an OpenHash
is a true Hash object, any object can be used as a key internally.
o = OpenHash.new
o[nil] = "Nothing"
o.to_h.assert == { nil=>"Nothing" }
It simply cannot be accessible via a reader method.
@@ -0,0 +1,17 @@
= QueryHash
A QueryHash is a Hash that provides open access much like an OpenHash, but it limits readers
to bang and query methods (i.e. method ending in `!` or `?`).
q = QueryHash.new
q.a = 1
q.b = 2
q.a?.assert == 1
q.b?.assert == 2
By default keys are converted to strings.
q.assert == { "a"=>1, "b"=>2 }
A QueryHash is compatible with Ruby's standard Hash in every other respect.
@@ -0,0 +1,12 @@
= CastingHash
A CastingHash is a Hash that allows _casting_ procedures to
defined that the keys and values pass through upon assignment.
c = CastingHash.new
c.cast_proc = lambda { |k,v| [k.to_s, v.to_s.upcase] }
c[:a] = 'a'
c.assert == {'a'=>'A'}
@@ -0,0 +1,20 @@
= StaticHash
A StaticHash is simply a Hash that can only be assigned
once per key. Once assigned a subsequent attempt to assign
a value to the same key will raise an ArgumentError.
h = StaticHash.new
h["x"] = 1
expect ArgumentError do
h["x"] = 2
end
The same error will be raised when using #update or #merge!.
expect ArgumentError do
h.update( "x"=>3 )
end
@@ -0,0 +1,17 @@
= KeyHash
The KeyHash is essentially the same as regular Hash but instead
of a `default_proc` the initializer takes the `key_proc` for
normalizing keys.
kh = KeyHash.new{ |k| k.to_s.upcase }
kh[:a] = 1
kh.to_h #=> ({'A'=>1})
By default, when no `key_proc` is given, it converts all keys to strings.
kh = KeyHash.new
kh[:a] = 1
kh.to_h #=> ({'a'=>1})
@@ -0,0 +1,64 @@
= OpenCascade
The reason this class is labeled "cascade", is that every internal
Hash is transformed into an OpenCascade dynamically upon access.
This makes it easy to create _cascading_ references.
h = { :x => { :y => { :z => 1 } } }
c = OpenCascade[h]
assert c.x.y.z == 1
As soon as you access a node it automatically becomes an OpenCascade.
c = OpenCascade.new
assert(OpenCascade === c.r)
assert(OpenCascade === c.a.b)
But if you set a node, then that will be it's value.
c.a.b = 4
assert c.a.b == 4
To query a node without causing the auto-creation of an OpenCasade
object, use the ?-mark.
assert c.a.z? == nil
OpenCascade also transforms Hashes within Arrays.
h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 }
c = OpenCascade[h]
assert c.x.first.a == 1
assert c.x.last.a == 2
Like OpenObject, OpenCascade allows you to insert entries as array
pairs.
c = OpenCascade.new
c << [:x,8]
c << [:y,9]
assert c.x == 8
assert c.y == 9
Finally, you can call methods ending in a !-mark to access the
underlying hash (Note that these differ in behavior from the
built-in !-methods).
bk = c.map!{ |k,v| k.to_s.upcase }
bk.sort.assert == ['X', 'Y']
So you can see that for the most an OpenCascade is just like
OpenHash, but it allows us to conveniently build open sub-layers
easily.
Enumerable still works with OpenCascades too.
h = {}
c = OpenCascade[:a=>1,:b=>{:c=>3}]
c.each do |k,v|
h[k] = v
end
OpenCascade.assert === h[:b]
@@ -0,0 +1,137 @@
= FuzzyHash
Should accept strings and retrieve based on them.
l = FuzzyHash.new
l['asd'] = 'qwe'
l['asd'].should == 'qwe'
Should accept strings, but the second time you set the same string, it should overwrite.
l = FuzzyHash.new
l['asd'] = 'asd'
l['asd'] = 'qwe'
l['asd'].should == 'qwe'
Should accept regexs too.
l = FuzzyHash.new
l[/asd.*/] = 'qwe'
l['asdqweasd'].should == 'qwe'
Should accept regexs too, but the second time you set the same regex, it should overwrite.
l = FuzzyHash.new
l[/asd/] = 'asd'
l[/asd/] = 'qwe'
l['asdqweasd'].should == 'qwe'
Should accept regexs too with the match.
l = FuzzyHash.new
l[/asd.*/] = 'qwe'
l.match_with_result('asdqweasd').should == ['qwe', 'asdqweasd']
Should accept regexs that match the whole strong too with the match.
l = FuzzyHash.new
l[/asd/] = 'qwe'
l.match_with_result('asd').should == ['qwe', 'asd']
Should prefer string to regex matches.
l = FuzzyHash.new
l['asd'] = 'qwe2'
l[/asd.*/] = 'qwe'
l['asd'].should == 'qwe2'
Should allow nil keys.
l = FuzzyHash.new
l[nil] = 'qwe2'
l['asd'] = 'qwe'
l['asd'].should == 'qwe'
l[nil].should == 'qwe2'
Should allow boolean keys.
l = FuzzyHash.new
l[false] = 'false'
l[true] = 'true'
l[/.*/] = 'everything else'
l[true].should == 'true'
l[false].should == 'false'
l['false'].should == 'everything else'
Should pick between the correct regex.
hash = FuzzyHash.new
hash[/^\d+$/] = 'number'
hash[/.*/] = 'something'
hash['123asd'].should == 'something'
Should be able to delete by value for hash.
l = FuzzyHash.new
l[nil] = 'qwe2'
l['asd'] = 'qwe'
l['asd'].should == 'qwe'
l[nil].should == 'qwe2'
l.delete_value('qwe2')
l[nil].should == nil
Should be able to delete by value for regex.
l = FuzzyHash.new
l[/qwe.*/] = 'qwe2'
l['asd'] = 'qwe'
l['asd'].should == 'qwe'
l['qweasd'].should == 'qwe2'
l.delete_value('qwe2')
l['qweasd'].should == nil
Should iterate through the keys.
l = FuzzyHash.new
l[/qwe.*/] = 'qwe2'
l['asd'] = 'qwe'
l['zxc'] = 'qwe'
l.keys.size.should == 3
Should iterate through the values.
l = FuzzyHash.new
l[/qwe.*/] = 'qwe2'
l['asd'] = 'qwe'
l['zxc'] = 'qwelkj'
(['qwe2','qwe','qwelkj'] & l.values).size.should == 3
Should clear.
l = FuzzyHash.new
l[/qwe.*/] = 'qwe2'
l['asd'] = 'qwe'
l['zxc'] = 'qwelkj'
l.clear
l.empty?.should == true
Should handle equality.
l_1 = FuzzyHash.new
l_1[/qwe.*/] = 'qwe2'
l_1['asd'] = 'qwelkj'
l_1['zxc'] = 'qwe'
l_2 = FuzzyHash.new
l_2['zxc'] = 'qwe'
l_2['asd'] = 'qwelkj'
l_2[/qwe.*/] = 'qwe2'
l_1.should == l_2
Should return the value when adding the value.
h = FuzzyHash.new
(h[/asd/] = '123').should == '123'
(h['qwe'] = '123').should == '123'
That's It.
@@ -0,0 +1,34 @@
= PropertyHash
The Property hash can be used an object in itself.
h = PropertyHash.new(:a=>1, :b=>2)
h[:a] #=> 1
h[:a] = 3
h[:a] #=> 3
Becuase the properties are fixed, if we try to set a key that is not present,
then we will get an error.
expect ArgumentError do
h[:x] = 5
end
The PropertyHash can also be used as a superclass.
class MyPropertyHash < PropertyHash
property :a, :default => 1
property :b, :default => 2
end
h = MyPropertyHash.new
h[:a] #=> 1
h[:a] = 3
h[:a] #=> 3
Again, if we try to set key that was not fixed, then we will get an error.
expect ArgumentError do
h[:x] = 5
end
@@ -0,0 +1,59 @@
= Association
An Association is a class for creating simple pairings.
require 'hashery/association'
An Association can bew created through the usual means
of instantiation.
Association.new(:a, :b)
Or the shortcut method #>> can be used in most cases.
:x >> :z
An association provides two methods to access its content, #index and #value.
a = 'foo' >> 'bar'
a.index.assert == 'foo'
a.value.assert == 'bar'
Associations can be used to create ordered-hashes via normal
arrays.
keys = []
vals = []
ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ]
ohash.each{ |k,v| keys << k ; vals << v }
keys.assert == ['A','B','C']
vals.assert == ['3','2','1']
Becuase Associations are objects in themselves more complex
collections can also be created.
complex = [
'parent' >> 'child',
'childless',
'another_parent' >> [
'subchildless',
'subparent' >> 'subchild'
]
]
An experimental feature of Association keeps a cache of all defined associations.
o = Object.new
o >> :a
o >> :b
o >> :c
o.associations.assert == [:a, :b, :c]
However this feature will probably be deprecated.
@@ -0,0 +1,2 @@
require 'ae'
require 'ae/should'
@@ -0,0 +1,3 @@
require 'hashery'
include Hashery